tcpGRO evaluates the TCP packet at pktI in bufs for coalescing with existing packets tracked in table. It returns a groResultNoop when no action was taken, groResultTableInsert when the evaluated packet was inserted into table, and groResultCoalesced when the evaluated packet was coalesced with anot
(bufs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool)
| 529 | // inserted into table, and groResultCoalesced when the evaluated packet was |
| 530 | // coalesced with another packet in table. |
| 531 | func tcpGRO(bufs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool) groResult { |
| 532 | pkt := bufs[pktI][offset:] |
| 533 | if len(pkt) > maxUint16 { |
| 534 | // A valid IPv4 or IPv6 packet will never exceed this. |
| 535 | return groResultNoop |
| 536 | } |
| 537 | iphLen := int((pkt[0] & 0x0F) * 4) |
| 538 | if isV6 { |
| 539 | iphLen = 40 |
| 540 | ipv6HPayloadLen := int(binary.BigEndian.Uint16(pkt[4:])) |
| 541 | if ipv6HPayloadLen != len(pkt)-iphLen { |
| 542 | return groResultNoop |
| 543 | } |
| 544 | } else { |
| 545 | totalLen := int(binary.BigEndian.Uint16(pkt[2:])) |
| 546 | if totalLen != len(pkt) { |
| 547 | return groResultNoop |
| 548 | } |
| 549 | } |
| 550 | if len(pkt) < iphLen { |
| 551 | return groResultNoop |
| 552 | } |
| 553 | tcphLen := int((pkt[iphLen+12] >> 4) * 4) |
| 554 | if tcphLen < 20 || tcphLen > 60 { |
| 555 | return groResultNoop |
| 556 | } |
| 557 | if len(pkt) < iphLen+tcphLen { |
| 558 | return groResultNoop |
| 559 | } |
| 560 | if !isV6 { |
| 561 | if pkt[6]&ipv4FlagMoreFragments != 0 || pkt[6]<<3 != 0 || pkt[7] != 0 { |
| 562 | // no GRO support for fragmented segments for now |
| 563 | return groResultNoop |
| 564 | } |
| 565 | } |
| 566 | tcpFlags := pkt[iphLen+tcpFlagsOffset] |
| 567 | var pshSet bool |
| 568 | // not a candidate if any non-ACK flags (except PSH+ACK) are set |
| 569 | if tcpFlags != tcpFlagACK { |
| 570 | if pkt[iphLen+tcpFlagsOffset] != tcpFlagACK|tcpFlagPSH { |
| 571 | return groResultNoop |
| 572 | } |
| 573 | pshSet = true |
| 574 | } |
| 575 | gsoSize := uint16(len(pkt) - tcphLen - iphLen) |
| 576 | // not a candidate if payload len is 0 |
| 577 | if gsoSize < 1 { |
| 578 | return groResultNoop |
| 579 | } |
| 580 | seq := binary.BigEndian.Uint32(pkt[iphLen+4:]) |
| 581 | srcAddrOffset := ipv4SrcAddrOffset |
| 582 | addrLen := 4 |
| 583 | if isV6 { |
| 584 | srcAddrOffset = ipv6SrcAddrOffset |
| 585 | addrLen = 16 |
| 586 | } |
| 587 | items, existing := table.lookupOrInsert(pkt, srcAddrOffset, srcAddrOffset+addrLen, iphLen, tcphLen, pktI) |
| 588 | if !existing { |
no test coverage detected