dhcp: fix dhcp proxy behavior for qinq and dot1q subinterfaces 62/26662/5
authorStanislav Zaikin <zstaseg@gmail.com>
Thu, 23 Apr 2020 12:14:30 +0000 (12:14 +0000)
committerJohn Lo <loj@cisco.com>
Sun, 26 Apr 2020 13:18:54 +0000 (13:18 +0000)
Previous behavior worked only when subinterface ID matches with dot1q tag and doesn't work at all in QinQ case.
In this patch I'm checking how subinterface is configured.

Type: fix

Signed-off-by: Stanislav Zaikin <zstaseg@gmail.com>
Change-Id: I7a662a0442fdc8e68aba5d6f469f3b1139a4bc2d

src/plugins/dhcp/dhcp4_proxy_node.c
src/plugins/dhcp/dhcp6_proxy_node.c

index 28c3e62..78c4444 100644 (file)
@@ -532,6 +532,8 @@ dhcp_proxy_to_client_input (vlib_main_t * vm,
          vnet_hw_interface_t *hi0;
          u32 sw_if_index = ~0;
          vnet_sw_interface_t *si0;
+         u32 inner_vlan = (u32) ~ 0;
+         u32 outer_vlan = (u32) ~ 0;
          u32 error0 = (u32) ~ 0;
          vnet_sw_interface_t *swif;
          u32 fib_index;
@@ -719,7 +721,19 @@ dhcp_proxy_to_client_input (vlib_main_t * vm,
          vlib_buffer_advance (b0, -(sizeof (ethernet_header_t)));
          si0 = vnet_get_sw_interface (vnm, original_sw_if_index);
          if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
-           vlib_buffer_advance (b0, -4 /* space for VLAN tag */ );
+           {
+             if (si0->sub.eth.flags.one_tag == 1)
+               {
+                 vlib_buffer_advance (b0, -4 /* space for 1 VLAN tag */ );
+                 outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x0800;
+               }
+             else if (si0->sub.eth.flags.two_tags == 1)
+               {
+                 vlib_buffer_advance (b0, -8 /* space for 2 VLAN tag */ );
+                 outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x8100;
+                 inner_vlan = (si0->sub.eth.inner_vlan_id << 16) | 0x0800;
+               }
+           }
 
          mac0 = vlib_buffer_get_current (b0);
 
@@ -728,15 +742,23 @@ dhcp_proxy_to_client_input (vlib_main_t * vm,
          clib_memcpy (mac0->src_address, ei0->address,
                       sizeof (ei0->address));
          clib_memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address));
-         mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ?
-           clib_net_to_host_u16 (0x8100) : clib_net_to_host_u16 (0x0800);
 
-         if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
+         if (si0->type == VNET_SW_INTERFACE_TYPE_SUB
+             && outer_vlan != (u32) ~ 0)
            {
+             mac0->type = (si0->sub.eth.flags.dot1ad == 1) ?
+               clib_net_to_host_u16 (0x88a8) : clib_net_to_host_u16 (0x8100);
              u32 *vlan_tag = (u32 *) (mac0 + 1);
-             u32 tmp;
-             tmp = (si0->sub.id << 16) | 0x0800;
-             *vlan_tag = clib_host_to_net_u32 (tmp);
+             *vlan_tag = clib_host_to_net_u32 (outer_vlan);
+             if (inner_vlan != (u32) ~ 0)
+               {
+                 u32 *inner_vlan_tag = (u32 *) (vlan_tag + 1);
+                 *inner_vlan_tag = clib_host_to_net_u32 (inner_vlan);
+               }
+           }
+         else
+           {
+             mac0->type = clib_net_to_host_u16 (0x0800);
            }
 
        do_trace:
index 95e5c92..3231f28 100644 (file)
@@ -595,6 +595,8 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm,
       u32 sw_if_index = ~0;
       u32 original_sw_if_index = ~0;
       vnet_sw_interface_t *si0;
+      u32 inner_vlan = (u32) ~ 0;
+      u32 outer_vlan = (u32) ~ 0;
       u32 error0 = (u32) ~ 0;
       vnet_sw_interface_t *swif;
       dhcpv6_option_t *r0 = 0, *o;
@@ -765,7 +767,19 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm,
       vlib_buffer_advance (b0, -(sizeof (ethernet_header_t)));
       si0 = vnet_get_sw_interface (vnm, original_sw_if_index);
       if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
-       vlib_buffer_advance (b0, -4 /* space for VLAN tag */ );
+       {
+         if (si0->sub.eth.flags.one_tag == 1)
+           {
+             vlib_buffer_advance (b0, -4 /* space for 1 VLAN tag */ );
+             outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x86dd;
+           }
+         else if (si0->sub.eth.flags.two_tags == 1)
+           {
+             vlib_buffer_advance (b0, -8 /* space for 2 VLAN tag */ );
+             outer_vlan = (si0->sub.eth.outer_vlan_id << 16) | 0x8100;
+             inner_vlan = (si0->sub.eth.inner_vlan_id << 16) | 0x86dd;
+           }
+       }
 
       mac0 = vlib_buffer_get_current (b0);
 
@@ -773,15 +787,22 @@ dhcpv6_proxy_to_client_input (vlib_main_t * vm,
       ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance);
       clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address));
       clib_memset (&mac0->dst_address, 0xff, sizeof (mac0->dst_address));
-      mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ?
-       clib_net_to_host_u16 (0x8100) : clib_net_to_host_u16 (0x86dd);
 
-      if (si0->type == VNET_SW_INTERFACE_TYPE_SUB)
+      if (si0->type == VNET_SW_INTERFACE_TYPE_SUB && outer_vlan != (u32) ~ 0)
        {
+         mac0->type = (si0->sub.eth.flags.dot1ad == 1) ?
+           clib_net_to_host_u16 (0x88a8) : clib_net_to_host_u16 (0x8100);
          u32 *vlan_tag = (u32 *) (mac0 + 1);
-         u32 tmp;
-         tmp = (si0->sub.id << 16) | 0x0800;
-         *vlan_tag = clib_host_to_net_u32 (tmp);
+         *vlan_tag = clib_host_to_net_u32 (outer_vlan);
+         if (inner_vlan != (u32) ~ 0)
+           {
+             u32 *inner_vlan_tag = (u32 *) (vlan_tag + 1);
+             *inner_vlan_tag = clib_host_to_net_u32 (inner_vlan);
+           }
+       }
+      else
+       {
+         mac0->type = clib_net_to_host_u16 (0x86dd);
        }
 
       /* $$$ consider adding a dynamic next to the graph node, for performance */