ip: add support for buffer offload metadata in ip midchain
[vpp.git] / src / vnet / ip / ip6_inlines.h
index ae7b7a1..9bd4752 100644 (file)
@@ -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]);
@@ -106,9 +117,20 @@ ip6_compute_flow_hash (const ip6_header_t * ip,
     }
 
   b ^= (flow_hash_config & IP_FLOW_HASH_PROTO) ? protocol : 0;
-  c = (flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ?
-    ((t1 << 16) | t2) : ((t2 << 16) | t1);
-
+  c = ((flow_hash_config & IP_FLOW_HASH_REVERSE_SRC_DST) ? ((t1 << 16) | t2) :
+                                                          ((t2 << 16) | t1));
+  t1 = ((u64) ip_flow_hash_router_id << 32);
+  t1 |=
+    ((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;
 }
@@ -129,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;
 }