GENEVE: shift/mask for header 88/9488/8
authorMarco Varlese <marco.varlese@suse.com>
Mon, 20 Nov 2017 08:20:38 +0000 (09:20 +0100)
committerNeale Ranns <nranns@cisco.com>
Fri, 24 Nov 2017 15:51:30 +0000 (15:51 +0000)
This patch addresses the bit-shifting/masking required to set/get specific
fields/bits in the GENEVE header.

Change-Id: I06ea6d3487c827ec2bc3edfc67c7cb97640d4fc3
Signed-off-by: Marco Varlese <marco.varlese@suse.com>
src/vnet/geneve/decap.c
src/vnet/geneve/geneve.c
src/vnet/geneve/geneve_packet.h

index db05214..2e6e9c5 100644 (file)
@@ -25,7 +25,7 @@ typedef struct
   u32 next_index;
   u32 tunnel_index;
   u32 error;
-  u32 vni;
+  u32 vni_rsvd;
 } geneve_rx_trace_t;
 
 static u8 *
@@ -40,12 +40,12 @@ format_geneve_rx_trace (u8 * s, va_list * args)
       s =
        format (s,
                "GENEVE decap from geneve_tunnel%d vni %d next %d error %d",
-               t->tunnel_index, t->vni, t->next_index, t->error);
+               t->tunnel_index, t->vni_rsvd, t->next_index, t->error);
     }
   else
     {
       s = format (s, "GENEVE decap error - tunnel for vni %d does not exist",
-                 t->vni);
+                 t->vni_rsvd);
     }
   return s;
 }
@@ -147,6 +147,10 @@ geneve_input (vlib_main_t * vm,
          /* udp leaves current_data pointing at the geneve header */
          geneve0 = vlib_buffer_get_current (b0);
          geneve1 = vlib_buffer_get_current (b1);
+
+         vnet_geneve_hdr_1word_ntoh (geneve0);
+         vnet_geneve_hdr_1word_ntoh (geneve1);
+
          if (is_ip4)
            {
              vlib_buffer_advance
@@ -198,13 +202,14 @@ geneve_input (vlib_main_t * vm,
          tunnel_index1 = ~0;
          error1 = 0;
 
-         if (PREDICT_FALSE (geneve0->ver != GENEVE_VERSION))
+         if (PREDICT_FALSE
+             (vnet_get_geneve_version (geneve0) != GENEVE_VERSION))
            {
              error0 = GENEVE_ERROR_BAD_FLAGS;
              next0 = GENEVE_INPUT_NEXT_DROP;
              goto trace0;
            }
-#if SUPPORT_OPTIONS_HEADER==0
+#if SUPPORT_OPTIONS_HEADER==1
          if (PREDICT_FALSE (vnet_get_geneve_critical_bit (geneve0) == 1))
            {
              error0 = GENEVE_ERROR_BAD_FLAGS;
@@ -215,7 +220,7 @@ geneve_input (vlib_main_t * vm,
          if (is_ip4)
            {
              key4_0.remote = ip4_0->src_address.as_u32;
-             key4_0.vni = geneve0->vni;
+             key4_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
 
              /* Make sure GENEVE tunnel exist according to packet SIP and VNI */
              if (PREDICT_FALSE (key4_0.as_u64 != last_key4.as_u64))
@@ -250,7 +255,7 @@ geneve_input (vlib_main_t * vm,
                  (ip4_address_is_multicast (&ip4_0->dst_address)))
                {
                  key4_0.remote = ip4_0->dst_address.as_u32;
-                 key4_0.vni = geneve0->vni;
+                 key4_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
                  /* Make sure mcast GENEVE tunnel exist by packet DIP and VNI */
                  p0 = hash_get (vxm->geneve4_tunnel_by_key, key4_0.as_u64);
                  if (PREDICT_TRUE (p0 != NULL))
@@ -268,7 +273,7 @@ geneve_input (vlib_main_t * vm,
            {
              key6_0.remote.as_u64[0] = ip6_0->src_address.as_u64[0];
              key6_0.remote.as_u64[1] = ip6_0->src_address.as_u64[1];
-             key6_0.vni = geneve0->vni;
+             key6_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
 
              /* Make sure GENEVE tunnel exist according to packet SIP and VNI */
              if (PREDICT_FALSE
@@ -305,7 +310,7 @@ geneve_input (vlib_main_t * vm,
                {
                  key6_0.remote.as_u64[0] = ip6_0->dst_address.as_u64[0];
                  key6_0.remote.as_u64[1] = ip6_0->dst_address.as_u64[1];
-                 key6_0.vni = geneve0->vni;
+                 key6_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
                  p0 = hash_get_mem (vxm->geneve6_tunnel_by_key, &key6_0);
                  if (PREDICT_TRUE (p0 != NULL))
                    {
@@ -361,16 +366,17 @@ geneve_input (vlib_main_t * vm,
              tr->next_index = next0;
              tr->error = error0;
              tr->tunnel_index = tunnel_index0;
-             tr->vni = vnet_get_geneve_vni (geneve0);
+             tr->vni_rsvd = vnet_get_geneve_vni (geneve0);
            }
 
-         if (PREDICT_FALSE (geneve1->ver != GENEVE_VERSION))
+         if (PREDICT_FALSE
+             (vnet_get_geneve_version (geneve1) != GENEVE_VERSION))
            {
              error1 = GENEVE_ERROR_BAD_FLAGS;
              next1 = GENEVE_INPUT_NEXT_DROP;
              goto trace1;
            }
-#if SUPPORT_OPTIONS_HEADER==0
+#if SUPPORT_OPTIONS_HEADER==1
          if (PREDICT_FALSE (vnet_get_geneve_critical_bit (geneve1) == 1))
            {
              error1 = GENEVE_ERROR_BAD_FLAGS;
@@ -381,7 +387,7 @@ geneve_input (vlib_main_t * vm,
          if (is_ip4)
            {
              key4_1.remote = ip4_1->src_address.as_u32;
-             key4_1.vni = geneve1->vni;
+             key4_1.vni = vnet_get_geneve_vni_bigendian (geneve1);
 
              /* Make sure unicast GENEVE tunnel exist by packet SIP and VNI */
              if (PREDICT_FALSE (key4_1.as_u64 != last_key4.as_u64))
@@ -416,7 +422,7 @@ geneve_input (vlib_main_t * vm,
                  (ip4_address_is_multicast (&ip4_1->dst_address)))
                {
                  key4_1.remote = ip4_1->dst_address.as_u32;
-                 key4_1.vni = geneve1->vni;
+                 key4_1.vni = vnet_get_geneve_vni_bigendian (geneve1);
                  /* Make sure mcast GENEVE tunnel exist by packet DIP and VNI */
                  p1 = hash_get (vxm->geneve4_tunnel_by_key, key4_1.as_u64);
                  if (PREDICT_TRUE (p1 != NULL))
@@ -434,7 +440,7 @@ geneve_input (vlib_main_t * vm,
            {
              key6_1.remote.as_u64[0] = ip6_1->src_address.as_u64[0];
              key6_1.remote.as_u64[1] = ip6_1->src_address.as_u64[1];
-             key6_1.vni = geneve1->vni;
+             key6_1.vni = vnet_get_geneve_vni_bigendian (geneve1);
 
              /* Make sure GENEVE tunnel exist according to packet SIP and VNI */
              if (PREDICT_FALSE
@@ -473,7 +479,7 @@ geneve_input (vlib_main_t * vm,
                {
                  key6_1.remote.as_u64[0] = ip6_1->dst_address.as_u64[0];
                  key6_1.remote.as_u64[1] = ip6_1->dst_address.as_u64[1];
-                 key6_1.vni = geneve1->vni;
+                 key6_1.vni = vnet_get_geneve_vni_bigendian (geneve1);
                  p1 = hash_get_mem (vxm->geneve6_tunnel_by_key, &key6_1);
                  if (PREDICT_TRUE (p1 != NULL))
                    {
@@ -529,7 +535,7 @@ geneve_input (vlib_main_t * vm,
              tr->next_index = next1;
              tr->error = error1;
              tr->tunnel_index = tunnel_index1;
-             tr->vni = vnet_get_geneve_vni (geneve1);
+             tr->vni_rsvd = vnet_get_geneve_vni (geneve1);
            }
 
          vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
@@ -564,6 +570,8 @@ geneve_input (vlib_main_t * vm,
 
          /* udp leaves current_data pointing at the geneve header */
          geneve0 = vlib_buffer_get_current (b0);
+         vnet_geneve_hdr_1word_ntoh (geneve0);
+
          if (is_ip4)
            {
              vlib_buffer_advance
@@ -598,13 +606,14 @@ geneve_input (vlib_main_t * vm,
          tunnel_index0 = ~0;
          error0 = 0;
 
-         if (PREDICT_FALSE (geneve0->ver != GENEVE_VERSION))
+         if (PREDICT_FALSE
+             (vnet_get_geneve_version (geneve0) != GENEVE_VERSION))
            {
              error0 = GENEVE_ERROR_BAD_FLAGS;
              next0 = GENEVE_INPUT_NEXT_DROP;
              goto trace00;
            }
-#if SUPPORT_OPTIONS_HEADER==0
+#if SUPPORT_OPTIONS_HEADER==1
          if (PREDICT_FALSE (vnet_get_geneve_critical_bit (geneve0) == 1))
            {
              error0 = GENEVE_ERROR_BAD_FLAGS;
@@ -615,7 +624,7 @@ geneve_input (vlib_main_t * vm,
          if (is_ip4)
            {
              key4_0.remote = ip4_0->src_address.as_u32;
-             key4_0.vni = geneve0->vni;
+             key4_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
 
              /* Make sure unicast GENEVE tunnel exist by packet SIP and VNI */
              if (PREDICT_FALSE (key4_0.as_u64 != last_key4.as_u64))
@@ -650,7 +659,7 @@ geneve_input (vlib_main_t * vm,
                  (ip4_address_is_multicast (&ip4_0->dst_address)))
                {
                  key4_0.remote = ip4_0->dst_address.as_u32;
-                 key4_0.vni = geneve0->vni;
+                 key4_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
                  /* Make sure mcast GENEVE tunnel exist by packet DIP and VNI */
                  p0 = hash_get (vxm->geneve4_tunnel_by_key, key4_0.as_u64);
                  if (PREDICT_TRUE (p0 != NULL))
@@ -668,7 +677,7 @@ geneve_input (vlib_main_t * vm,
            {
              key6_0.remote.as_u64[0] = ip6_0->src_address.as_u64[0];
              key6_0.remote.as_u64[1] = ip6_0->src_address.as_u64[1];
-             key6_0.vni = geneve0->vni;
+             key6_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
 
              /* Make sure GENEVE tunnel exist according to packet SIP and VNI */
              if (PREDICT_FALSE
@@ -705,7 +714,7 @@ geneve_input (vlib_main_t * vm,
                {
                  key6_0.remote.as_u64[0] = ip6_0->dst_address.as_u64[0];
                  key6_0.remote.as_u64[1] = ip6_0->dst_address.as_u64[1];
-                 key6_0.vni = geneve0->vni;
+                 key6_0.vni = vnet_get_geneve_vni_bigendian (geneve0);
                  p0 = hash_get_mem (vxm->geneve6_tunnel_by_key, &key6_0);
                  if (PREDICT_TRUE (p0 != NULL))
                    {
@@ -761,7 +770,7 @@ geneve_input (vlib_main_t * vm,
              tr->next_index = next0;
              tr->error = error0;
              tr->tunnel_index = tunnel_index0;
-             tr->vni = vnet_get_geneve_vni (geneve0);
+             tr->vni_rsvd = vnet_get_geneve_vni (geneve0);
            }
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
                                           to_next, n_left_to_next,
index 86250e9..25bf4a4 100644 (file)
@@ -32,9 +32,6 @@
  * This makes it possible for servers to be co-located in the same data
  * center or be separated geographically as long as they are reachable
  * through the underlay L3 network.
- *
- * You can refer to this kind of L2 overlay bridge domain as a GENEVE
- * (Virtual eXtensible VLAN) segment.
  */
 
 
@@ -272,6 +269,9 @@ geneve_rewrite (geneve_tunnel_t * t, bool is_ip6)
   vnet_set_geneve_oamframe_bit (geneve, 0);
   vnet_set_geneve_critical_bit (geneve, 0);
   vnet_set_geneve_protocol (geneve, GENEVE_ETH_PROTOCOL);
+
+  vnet_geneve_hdr_1word_hton (geneve);
+
   vnet_set_geneve_vni (geneve, t->vni);
 
   t->rewrite = r.rw;
@@ -404,13 +404,15 @@ int vnet_geneve_add_del_tunnel
   if (!is_ip6)
     {
       key4.remote = a->remote.ip4.as_u32;
-      key4.vni = clib_host_to_net_u32 (a->vni << 8);
+      key4.vni =
+       clib_host_to_net_u32 ((a->vni << GENEVE_VNI_SHIFT) & GENEVE_VNI_MASK);
       p = hash_get (vxm->geneve4_tunnel_by_key, key4.as_u64);
     }
   else
     {
       key6.remote = a->remote.ip6;
-      key6.vni = clib_host_to_net_u32 (a->vni << 8);
+      key6.vni =
+       clib_host_to_net_u32 ((a->vni << GENEVE_VNI_SHIFT) & GENEVE_VNI_MASK);
       p = hash_get_mem (vxm->geneve6_tunnel_by_key, &key6);
     }
 
index 87e5225..ab37f53 100644 (file)
 #define INT_OPT_CLASS    0x0103
 #define VMWARE_OPT_CLASS 0x0104
 
+/*
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          Option Class         |      Type     |R|R|R| Length  |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      Variable Option Data                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
 typedef struct
 {
   u16 opt_class;
   u8 type;
-  u8 res:3;
-  u8 length:5;
+  /* The 3 reserved bits are for future use;
+   * Need to be 0 on sending and ignored on receipt.
+   */
+  u8 res;
+  /* Length is expressed in 4-bytes multiples excluding the options header. */
+  u8 length;
   u32 opt_data[];
 } geneve_options_t;
 
@@ -87,88 +100,146 @@ typedef struct
 
 typedef struct
 {
-  u8 ver:2;
-  u8 opt_len:6;
-  u8 oam_frame:1;
-  u8 critical_options:1;
-  u8 res1:6;
-  u16 protocol;
-  u32 vni:24;
-  u8 res2;
+  /*
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  u32 first_word;
+
+  /*
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |        Virtual Network Identifier (VNI)       |    Reserved   |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   */
+  u32 vni_rsvd;
   geneve_options_t opts[];
 } geneve_header_t;
 
+#define GENEVE_VERSION_SHIFT   30
+#define GENEVE_OPTLEN_SHIFT            24
+#define GENEVE_O_BIT_SHIFT             23
+#define GENEVE_C_BIT_SHIFT             22
+#define GENEVE_6_RESERVED_SHIFT 16
+#define GENEVE_VNI_SHIFT               8
+
+#define GENEVE_VERSION_MASK            0xC0000000
+#define GENEVE_OPTLEN_MASK             0x3F000000
+#define GENEVE_O_BIT_MASK              0x00800000
+#define GENEVE_C_BIT_MASK              0x00400000
+#define GENEVE_6_RESERVED_MASK 0x003F0000
+#define GENEVE_PROTOCOL_MASK   0x0000FFFF
+#define GENEVE_VNI_MASK                        0xFFFFFF00
+
+/*
+ * Return the VNI in host-byte order
+ */
 static inline u32
 vnet_get_geneve_vni (geneve_header_t * h)
 {
-  return (clib_net_to_host_u32 (h->vni) >> 8);
+  return (clib_net_to_host_u32 (h->vni_rsvd & GENEVE_VNI_MASK) >>
+         GENEVE_VNI_SHIFT);
+}
+
+/*
+ * Return the VNI in network-byte order
+ *
+ * To be used in the DECAP phase to create the lookup key (IP + VNI)
+ */
+static inline u32
+vnet_get_geneve_vni_bigendian (geneve_header_t * h)
+{
+  u32 vni_host = vnet_get_geneve_vni (h);
+  return clib_host_to_net_u32 ((vni_host << GENEVE_VNI_SHIFT) &
+                              GENEVE_VNI_MASK);
 }
 
 static inline void
 vnet_set_geneve_vni (geneve_header_t * h, u32 vni)
 {
-  h->vni = clib_host_to_net_u32 (vni << 8);
+  h->vni_rsvd &= ~(GENEVE_VNI_MASK);
+  h->vni_rsvd |=
+    clib_host_to_net_u32 ((vni << GENEVE_VNI_SHIFT) & GENEVE_VNI_MASK);
 }
 
 static inline u8
 vnet_get_geneve_version (geneve_header_t * h)
 {
-  return (clib_net_to_host_u32 (h->ver) >> 30);
+  return ((h->first_word & GENEVE_VERSION_MASK) >> GENEVE_VERSION_SHIFT);
 }
 
 static inline void
 vnet_set_geneve_version (geneve_header_t * h, u8 version)
 {
-  h->ver = clib_host_to_net_u32 (version << 30);
+  h->first_word &= ~(GENEVE_VERSION_MASK);
+  h->first_word |= ((version << GENEVE_VERSION_SHIFT) & GENEVE_VERSION_MASK);
 }
 
 static inline u8
 vnet_get_geneve_options_len (geneve_header_t * h)
 {
-  return (clib_net_to_host_u32 (h->opt_len) >> 24);
+  return ((h->first_word & GENEVE_OPTLEN_MASK) >> GENEVE_OPTLEN_SHIFT);
 }
 
 static inline void
 vnet_set_geneve_options_len (geneve_header_t * h, u8 len)
 {
-  h->opt_len = clib_host_to_net_u32 (len << 24);
+  h->first_word &= ~(GENEVE_OPTLEN_MASK);
+  h->first_word |= ((len << GENEVE_OPTLEN_SHIFT) & GENEVE_OPTLEN_MASK);
 }
 
 static inline u8
 vnet_get_geneve_oamframe_bit (geneve_header_t * h)
 {
-  return (clib_net_to_host_u32 (h->oam_frame) >> 23);
+  return ((h->first_word & GENEVE_O_BIT_MASK) >> GENEVE_O_BIT_SHIFT);
 }
 
 static inline void
 vnet_set_geneve_oamframe_bit (geneve_header_t * h, u8 oam)
 {
-  h->oam_frame = clib_host_to_net_u32 (oam << 23);
+  h->first_word &= ~(GENEVE_O_BIT_MASK);
+  h->first_word |= ((oam << GENEVE_O_BIT_SHIFT) & GENEVE_O_BIT_MASK);
 }
 
 static inline u8
 vnet_get_geneve_critical_bit (geneve_header_t * h)
 {
-  return (clib_net_to_host_u32 (h->critical_options) >> 22);
+  return ((h->first_word & GENEVE_C_BIT_MASK) >> GENEVE_C_BIT_SHIFT);
 }
 
 static inline void
 vnet_set_geneve_critical_bit (geneve_header_t * h, u8 critical_opts)
 {
-  h->critical_options = clib_host_to_net_u32 (critical_opts << 22);
+  h->first_word &= ~(GENEVE_C_BIT_MASK);
+  h->first_word |=
+    ((critical_opts << GENEVE_C_BIT_SHIFT) & GENEVE_C_BIT_MASK);
 }
 
 static inline u16
 vnet_get_geneve_protocol (geneve_header_t * h)
 {
-  return clib_net_to_host_u32 (h->protocol);
+  return (h->first_word & GENEVE_PROTOCOL_MASK);
 }
 
 static inline void
 vnet_set_geneve_protocol (geneve_header_t * h, u16 protocol)
 {
-  h->protocol = clib_host_to_net_u32 (protocol);
+  h->first_word &= ~(GENEVE_PROTOCOL_MASK);
+  h->first_word |= (protocol & GENEVE_PROTOCOL_MASK);
 }
+
+static inline void
+vnet_geneve_hdr_1word_ntoh (geneve_header_t * h)
+{
+  h->first_word = clib_net_to_host_u32 (h->first_word);
+}
+
+static inline void
+vnet_geneve_hdr_1word_hton (geneve_header_t * h)
+{
+  h->first_word = clib_host_to_net_u32 (h->first_word);
+}
+
 #endif
 
 /*