handleGRO evaluates bufs for GRO, and writes the indices of the resulting packets into toWrite. toWrite, tcpTable, and udpTable should initially be empty (but non-nil), and are passed in to save allocs as the caller may reset and recycle them across vectors of packets. canUDPGRO indicates if UDP GRO
(bufs [][]byte, offset int, tcpTable *tcpGROTable, udpTable *udpGROTable, canUDPGRO bool, toWrite *[]int)
| 863 | // and recycle them across vectors of packets. canUDPGRO indicates if UDP GRO is |
| 864 | // supported. |
| 865 | func handleGRO(bufs [][]byte, offset int, tcpTable *tcpGROTable, udpTable *udpGROTable, canUDPGRO bool, toWrite *[]int) error { |
| 866 | for i := range bufs { |
| 867 | if offset < virtioNetHdrLen || offset > len(bufs[i])-1 { |
| 868 | return errors.New("invalid offset") |
| 869 | } |
| 870 | var result groResult |
| 871 | switch packetIsGROCandidate(bufs[i][offset:], canUDPGRO) { |
| 872 | case tcp4GROCandidate: |
| 873 | result = tcpGRO(bufs, offset, i, tcpTable, false) |
| 874 | case tcp6GROCandidate: |
| 875 | result = tcpGRO(bufs, offset, i, tcpTable, true) |
| 876 | case udp4GROCandidate: |
| 877 | result = udpGRO(bufs, offset, i, udpTable, false) |
| 878 | case udp6GROCandidate: |
| 879 | result = udpGRO(bufs, offset, i, udpTable, true) |
| 880 | } |
| 881 | switch result { |
| 882 | case groResultNoop: |
| 883 | hdr := virtioNetHdr{} |
| 884 | err := hdr.encode(bufs[i][offset-virtioNetHdrLen:]) |
| 885 | if err != nil { |
| 886 | return err |
| 887 | } |
| 888 | fallthrough |
| 889 | case groResultTableInsert: |
| 890 | *toWrite = append(*toWrite, i) |
| 891 | } |
| 892 | } |
| 893 | errTCP := applyTCPCoalesceAccounting(bufs, offset, tcpTable) |
| 894 | errUDP := applyUDPCoalesceAccounting(bufs, offset, udpTable) |
| 895 | return errors.Join(errTCP, errUDP) |
| 896 | } |
| 897 | |
| 898 | // gsoSplit splits packets from in into outBuffs, writing the size of each |
| 899 | // element into sizes. It returns the number of buffers populated, and/or an |