diff options
Diffstat (limited to 'src/vnet/ip/ip6_inlines.h')
-rw-r--r-- | src/vnet/ip/ip6_inlines.h | 103 |
1 files changed, 36 insertions, 67 deletions
diff --git a/src/vnet/ip/ip6_inlines.h b/src/vnet/ip/ip6_inlines.h index 2a4bb70573b..9bd475224eb 100644 --- a/src/vnet/ip/ip6_inlines.h +++ b/src/vnet/ip/ip6_inlines.h @@ -49,29 +49,40 @@ always_inline u32 ip6_compute_flow_hash (const ip6_header_t * ip, flow_hash_config_t flow_hash_config) { - tcp_header_t *tcp; + const tcp_header_t *tcp; + const udp_header_t *udp = (void *) (ip + 1); + const gtpv1u_header_t *gtpu = (void *) (udp + 1); u64 a, b, c; u64 t1, t2; + u32 t3; uword is_tcp_udp = 0; u8 protocol = ip->protocol; + uword is_udp = protocol == IP_PROTOCOL_UDP; - if (PREDICT_TRUE - ((ip->protocol == IP_PROTOCOL_TCP) - || (ip->protocol == IP_PROTOCOL_UDP))) + if (PREDICT_TRUE ((protocol == IP_PROTOCOL_TCP) || is_udp)) { is_tcp_udp = 1; tcp = (void *) (ip + 1); } - else if (ip->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS) + else { - ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip + 1); - if ((hbh->protocol == IP_PROTOCOL_TCP) || - (hbh->protocol == IP_PROTOCOL_UDP)) + const void *cur = ip + 1; + if (protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS) + { + const ip6_hop_by_hop_header_t *hbh = cur; + protocol = hbh->protocol; + cur += (hbh->length + 1) * 8; + } + if (protocol == IP_PROTOCOL_IPV6_FRAGMENTATION) + { + const ip6_fragment_ext_header_t *frag = cur; + protocol = frag->protocol; + } + else if (protocol == IP_PROTOCOL_TCP || protocol == IP_PROTOCOL_UDP) { is_tcp_udp = 1; - tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3)); + tcp = cur; } - protocol = hbh->protocol; } t1 = (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1]); @@ -113,7 +124,13 @@ ip6_compute_flow_hash (const ip6_header_t * ip, ((flow_hash_config & IP_FLOW_HASH_FL) ? ip6_flow_label_network_order (ip) : 0); c ^= t1; - + if (PREDICT_TRUE (is_udp) && + PREDICT_FALSE ((flow_hash_config & IP_FLOW_HASH_GTPV1_TEID) && + udp->dst_port == GTPV1_PORT_BE)) + { + t3 = gtpu->teid; + a ^= t3; + } hash_mix64 (a, b, c); return (u32) c; } @@ -134,65 +151,17 @@ ip6_compute_flow_hash (const ip6_header_t * ip, * it is a non-first fragment -1 is returned. */ always_inline int -ip6_locate_header (vlib_buffer_t * p0, - ip6_header_t * ip0, int find_hdr_type, u32 * offset) +ip6_locate_header (vlib_buffer_t *b, ip6_header_t *ip, int find_hdr_type, + u32 *offset) { - u8 next_proto = ip0->protocol; - u8 *next_header; - u8 done = 0; - u32 cur_offset; - u8 *temp_nxthdr = 0; - u32 exthdr_len = 0; - - next_header = ip6_next_header (ip0); - cur_offset = sizeof (ip6_header_t); - while (1) + ip6_ext_hdr_chain_t hdr_chain; + int res = ip6_ext_header_walk (b, ip, find_hdr_type, &hdr_chain); + if (res >= 0) { - done = (next_proto == find_hdr_type); - if (PREDICT_FALSE - (next_header >= - (u8 *) vlib_buffer_get_current (p0) + p0->current_length)) - { - //A malicious packet could set an extension header with a too big size - return (-1); - } - if (done) - break; - if ((!ip6_ext_hdr (next_proto)) || next_proto == IP_PROTOCOL_IP6_NONXT) - { - if (find_hdr_type < 0) - break; - return -1; - } - if (next_proto == IP_PROTOCOL_IPV6_FRAGMENTATION) - { - ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) next_header; - u16 frag_off = ip6_frag_hdr_offset (frag_hdr); - /* Non first fragment return -1 */ - if (frag_off) - return (-1); - exthdr_len = sizeof (ip6_frag_hdr_t); - temp_nxthdr = next_header + exthdr_len; - } - else if (next_proto == IP_PROTOCOL_IPSEC_AH) - { - exthdr_len = - ip6_ext_authhdr_len (((ip6_ext_header_t *) next_header)); - temp_nxthdr = next_header + exthdr_len; - } - else - { - exthdr_len = - ip6_ext_header_len (((ip6_ext_header_t *) next_header)); - temp_nxthdr = next_header + exthdr_len; - } - next_proto = ((ip6_ext_header_t *) next_header)->next_hdr; - next_header = temp_nxthdr; - cur_offset += exthdr_len; + *offset = hdr_chain.eh[res].offset; + return hdr_chain.eh[res].protocol; } - - *offset = cur_offset; - return (next_proto); + return -1; } |