Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_lro.c
Context not available. | |||||
}; | }; | ||||
static inline void * | static inline void * | ||||
tcp_lro_low_level_parser(void *ptr, struct lro_parser *parser, bool update_data, bool is_vxlan) | tcp_lro_low_level_parser(void *ptr, struct lro_parser *parser, bool update_data, bool is_vxlan, int mlen) | ||||
{ | { | ||||
const struct ether_vlan_header *eh; | const struct ether_vlan_header *eh; | ||||
void *old; | void *old; | ||||
Context not available. | |||||
} | } | ||||
/* advance to next header */ | /* advance to next header */ | ||||
ptr = (uint8_t *)ptr + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | ptr = (uint8_t *)ptr + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | ||||
mlen -= (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); | |||||
} else { | } else { | ||||
eth_type = eh->evl_encap_proto; | eth_type = eh->evl_encap_proto; | ||||
/* advance to next header */ | /* advance to next header */ | ||||
mlen -= ETHER_HDR_LEN; | |||||
ptr = (uint8_t *)ptr + ETHER_HDR_LEN; | ptr = (uint8_t *)ptr + ETHER_HDR_LEN; | ||||
} | } | ||||
if (__predict_false(mlen <= 0)) | |||||
return (NULL); | |||||
switch (eth_type) { | switch (eth_type) { | ||||
#ifdef INET | #ifdef INET | ||||
case htons(ETHERTYPE_IP): | case htons(ETHERTYPE_IP): | ||||
parser->ip4 = ptr; | parser->ip4 = ptr; | ||||
if (__predict_false(mlen < sizeof(struct ip))) | |||||
return (NULL); | |||||
/* Ensure there are no IPv4 options. */ | /* Ensure there are no IPv4 options. */ | ||||
if ((parser->ip4->ip_hl << 2) != sizeof (*parser->ip4)) | if ((parser->ip4->ip_hl << 2) != sizeof (*parser->ip4)) | ||||
break; | break; | ||||
Context not available. | |||||
if (parser->ip4->ip_off & htons(IP_MF|IP_OFFMASK)) | if (parser->ip4->ip_off & htons(IP_MF|IP_OFFMASK)) | ||||
break; | break; | ||||
ptr = (uint8_t *)ptr + (parser->ip4->ip_hl << 2); | ptr = (uint8_t *)ptr + (parser->ip4->ip_hl << 2); | ||||
mlen -= sizeof(struct ip); | |||||
if (update_data) { | if (update_data) { | ||||
parser->data.s_addr.v4 = parser->ip4->ip_src; | parser->data.s_addr.v4 = parser->ip4->ip_src; | ||||
parser->data.d_addr.v4 = parser->ip4->ip_dst; | parser->data.d_addr.v4 = parser->ip4->ip_dst; | ||||
} | } | ||||
switch (parser->ip4->ip_p) { | switch (parser->ip4->ip_p) { | ||||
case IPPROTO_UDP: | case IPPROTO_UDP: | ||||
if (__predict_false(mlen < sizeof(struct udphdr))) | |||||
return (NULL); | |||||
parser->udp = ptr; | parser->udp = ptr; | ||||
if (update_data) { | if (update_data) { | ||||
parser->data.lro_type = LRO_TYPE_IPV4_UDP; | parser->data.lro_type = LRO_TYPE_IPV4_UDP; | ||||
Context not available. | |||||
return (ptr); | return (ptr); | ||||
case IPPROTO_TCP: | case IPPROTO_TCP: | ||||
parser->tcp = ptr; | parser->tcp = ptr; | ||||
if (__predict_false(mlen < sizeof(struct tcphdr))) | |||||
return (NULL); | |||||
if (update_data) { | if (update_data) { | ||||
parser->data.lro_type = LRO_TYPE_IPV4_TCP; | parser->data.lro_type = LRO_TYPE_IPV4_TCP; | ||||
parser->data.s_port = parser->tcp->th_sport; | parser->data.s_port = parser->tcp->th_sport; | ||||
Context not available. | |||||
} else { | } else { | ||||
MPASS(parser->data.lro_type == LRO_TYPE_IPV4_TCP); | MPASS(parser->data.lro_type == LRO_TYPE_IPV4_TCP); | ||||
} | } | ||||
if (__predict_false(mlen < (parser->tcp->th_off << 2))) | |||||
return (NULL); | |||||
ptr = (uint8_t *)ptr + (parser->tcp->th_off << 2); | ptr = (uint8_t *)ptr + (parser->tcp->th_off << 2); | ||||
parser->total_hdr_len = (uint8_t *)ptr - (uint8_t *)old; | parser->total_hdr_len = (uint8_t *)ptr - (uint8_t *)old; | ||||
return (ptr); | return (ptr); | ||||
Context not available. | |||||
#ifdef INET6 | #ifdef INET6 | ||||
case htons(ETHERTYPE_IPV6): | case htons(ETHERTYPE_IPV6): | ||||
parser->ip6 = ptr; | parser->ip6 = ptr; | ||||
if (__predict_false(mlen < sizeof(struct ip6_hdr))) | |||||
return (NULL); | |||||
ptr = (uint8_t *)ptr + sizeof(*parser->ip6); | ptr = (uint8_t *)ptr + sizeof(*parser->ip6); | ||||
if (update_data) { | if (update_data) { | ||||
parser->data.s_addr.v6 = parser->ip6->ip6_src; | parser->data.s_addr.v6 = parser->ip6->ip6_src; | ||||
parser->data.d_addr.v6 = parser->ip6->ip6_dst; | parser->data.d_addr.v6 = parser->ip6->ip6_dst; | ||||
} | } | ||||
mlen -= sizeof(struct ip6_hdr); | |||||
switch (parser->ip6->ip6_nxt) { | switch (parser->ip6->ip6_nxt) { | ||||
case IPPROTO_UDP: | case IPPROTO_UDP: | ||||
if (__predict_false(mlen < sizeof(struct udphdr))) | |||||
return (NULL); | |||||
parser->udp = ptr; | parser->udp = ptr; | ||||
if (update_data) { | if (update_data) { | ||||
parser->data.lro_type = LRO_TYPE_IPV6_UDP; | parser->data.lro_type = LRO_TYPE_IPV6_UDP; | ||||
Context not available. | |||||
parser->total_hdr_len = (uint8_t *)ptr - (uint8_t *)old; | parser->total_hdr_len = (uint8_t *)ptr - (uint8_t *)old; | ||||
return (ptr); | return (ptr); | ||||
case IPPROTO_TCP: | case IPPROTO_TCP: | ||||
if (__predict_false(mlen < sizeof(struct tcphdr))) | |||||
return (NULL); | |||||
parser->tcp = ptr; | parser->tcp = ptr; | ||||
if (update_data) { | if (update_data) { | ||||
parser->data.lro_type = LRO_TYPE_IPV6_TCP; | parser->data.lro_type = LRO_TYPE_IPV6_TCP; | ||||
Context not available. | |||||
} else { | } else { | ||||
MPASS(parser->data.lro_type == LRO_TYPE_IPV6_TCP); | MPASS(parser->data.lro_type == LRO_TYPE_IPV6_TCP); | ||||
} | } | ||||
if (__predict_false(mlen < (parser->tcp->th_off << 2))) | |||||
return (NULL); | |||||
ptr = (uint8_t *)ptr + (parser->tcp->th_off << 2); | ptr = (uint8_t *)ptr + (parser->tcp->th_off << 2); | ||||
parser->total_hdr_len = (uint8_t *)ptr - (uint8_t *)old; | parser->total_hdr_len = (uint8_t *)ptr - (uint8_t *)old; | ||||
return (ptr); | return (ptr); | ||||
Context not available. | |||||
void *data_ptr; | void *data_ptr; | ||||
/* Try to parse outer headers first. */ | /* Try to parse outer headers first. */ | ||||
data_ptr = tcp_lro_low_level_parser(m->m_data, po, update_data, false); | data_ptr = tcp_lro_low_level_parser(m->m_data, po, update_data, false, m->m_len); | ||||
if (data_ptr == NULL || po->total_hdr_len > m->m_len) | if (data_ptr == NULL || po->total_hdr_len > m->m_len) | ||||
return (NULL); | return (NULL); | ||||
Context not available. | |||||
break; | break; | ||||
/* Try to parse inner headers. */ | /* Try to parse inner headers. */ | ||||
data_ptr = tcp_lro_low_level_parser(data_ptr, pi, update_data, true); | data_ptr = tcp_lro_low_level_parser(data_ptr, pi, update_data, true, | ||||
hselasky: You would need to adjust the length here:
m->m_len - (data_ptr - m->m_data)
This is the inner… | |||||
Not Done Inline ActionsOr: hselasky: Or:
m->m_len - po->total_hdr_len | |||||
Done Inline ActionsAhh good point about the inner header ... rrs: Ahh good point about the inner header ... | |||||
if (data_ptr == NULL || pi->total_hdr_len > m->m_len) | (m->m_len - ((caddr_t)data_ptr - m->m_data))); | ||||
Not Done Inline ActionsYes, one bug here: pi->total_hdr_len > m->m_len Should be: po->total_hdr_len + pi->total_hdr_len > m->m_len hselasky: Yes, one bug here:
```
pi->total_hdr_len > m->m_len
```
Should be:
```
po->total_hdr_len +… | |||||
Done Inline ActionsWe might not even need the condition if we just monitor the m->m_len as the parser runs, it will return NULL rrs: We might not even need the condition if we just monitor the m->m_len as the parser runs, it… | |||||
Not Done Inline ActionsYes, if the length is checked for all cases in tcp_lro_low_level_parser() including VXLAN, then you can remove those checks! hselasky: Yes, if the length is checked for all cases in tcp_lro_low_level_parser() including VXLAN, then… | |||||
if (data_ptr == NULL || (pi->total_hdr_len + po->total_hdr_len) > m->m_len) | |||||
break; | break; | ||||
/* Verify supported header types. */ | /* Verify supported header types. */ | ||||
Context not available. |
You would need to adjust the length here:
m->m_len - (data_ptr - m->m_data)
This is the inner header.