Add Support of DHCP VSS Type 0 where VPN-ID is ASCII 20/9420/4
authorJohn Lo <loj@cisco.com>
Tue, 14 Nov 2017 18:19:26 +0000 (13:19 -0500)
committerDave Barach <openvpp@barachs.net>
Thu, 16 Nov 2017 11:25:51 +0000 (11:25 +0000)
Enhence support of DHCP VSS (Virtual Subnet Selection) to include
VSS type 0 where VSS info is a NVT (Network Virtual Terminal)
ASCII VPN ID where the ASCII string MUST NOT be terminated with a
zero byte. Existing code already support VSS type 1, where VSS
information is a RFC 2685 VPN-ID of 7 bytes with 3 bytes OUI
and 4 bytes VPN index, and VSS type 255 indicating global VPN.

Change-Id: I54edbc447c89a2aacd1cc9fc72bd5ba386037608
Signed-off-by: John Lo <loj@cisco.com>
src/vat/api_format.c
src/vnet/dhcp/dhcp.api
src/vnet/dhcp/dhcp4_proxy_node.c
src/vnet/dhcp/dhcp6_packet.h
src/vnet/dhcp/dhcp6_proxy_node.c
src/vnet/dhcp/dhcp_api.c
src/vnet/dhcp/dhcp_proxy.c
src/vnet/dhcp/dhcp_proxy.h
src/vpp/api/custom_dump.c
test/test_dhcp.py
test/vpp_papi_provider.py

index 612fba6..cfdce0b 100644 (file)
@@ -50,6 +50,7 @@
 #include <vnet/policer/policer.h>
 #include <vnet/policer/police.h>
 #include <vnet/mfib/mfib_types.h>
+#include <vnet/dhcp/dhcp_proxy.h>
 
 #include "vat/json_format.h"
 
@@ -7060,7 +7061,7 @@ api_bridge_domain_add_del (vat_main_t * vam)
       goto done;
     }
 
-  if ((bd_tag) && (strlen ((char *) bd_tag) > 63))
+  if ((bd_tag) && (vec_len (bd_tag) > 63))
     {
       errmsg ("bd-tag cannot be longer than 63");
       ret = -99;
@@ -7078,8 +7079,10 @@ api_bridge_domain_add_del (vat_main_t * vam)
   mp->is_add = is_add;
   mp->mac_age = (u8) mac_age;
   if (bd_tag)
-    strcpy ((char *) mp->bd_tag, (char *) bd_tag);
-
+    {
+      clib_memcpy (mp->bd_tag, bd_tag, vec_len (bd_tag));
+      mp->bd_tag[vec_len (bd_tag)] = 0;
+    }
   S (mp);
   W (ret);
 
@@ -9337,15 +9340,19 @@ vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp)
 
   if (mp->is_ipv6)
     print (vam->ofp,
-          "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d",
+          "RX Table-ID %d, Source Address %U, VSS Type %d, "
+          "VSS VPN-ID '%s', VSS FIB-ID %d, VSS OUI %d",
           ntohl (mp->rx_vrf_id),
           format_ip6_address, mp->dhcp_src_address,
+          mp->vss_type, mp->vss_vpn_ascii_id,
           ntohl (mp->vss_oui), ntohl (mp->vss_fib_id));
   else
     print (vam->ofp,
-          "RX Table-ID %d, Source Address %U, VSS FIB-ID %d, VSS OUI %d",
+          "RX Table-ID %d, Source Address %U, VSS Type %d, "
+          "VSS VPN-ID '%s', VSS FIB-ID %d, VSS OUI %d",
           ntohl (mp->rx_vrf_id),
           format_ip4_address, mp->dhcp_src_address,
+          mp->vss_type, mp->vss_vpn_ascii_id,
           ntohl (mp->vss_oui), ntohl (mp->vss_fib_id));
 
   for (i = 0; i < count; i++)
@@ -9382,6 +9389,10 @@ static void vl_api_dhcp_proxy_details_t_handler_json
 
   vat_json_init_object (node);
   vat_json_object_add_uint (node, "rx-table-id", ntohl (mp->rx_vrf_id));
+  vat_json_object_add_bytes (node, "vss-type", &mp->vss_type,
+                            sizeof (mp->vss_type));
+  vat_json_object_add_string_copy (node, "vss-vpn-ascii-id",
+                                  mp->vss_vpn_ascii_id);
   vat_json_object_add_uint (node, "vss-fib-id", ntohl (mp->vss_fib_id));
   vat_json_object_add_uint (node, "vss-oui", ntohl (mp->vss_oui));
 
@@ -9456,59 +9467,62 @@ api_dhcp_proxy_set_vss (vat_main_t * vam)
   vl_api_dhcp_proxy_set_vss_t *mp;
   u8 is_ipv6 = 0;
   u8 is_add = 1;
-  u32 tbl_id;
-  u8 tbl_id_set = 0;
-  u32 oui;
-  u8 oui_set = 0;
-  u32 fib_id;
-  u8 fib_id_set = 0;
+  u32 tbl_id = ~0;
+  u8 vss_type = VSS_TYPE_DEFAULT;
+  u8 *vpn_ascii_id = 0;
+  u32 oui = 0;
+  u32 fib_id = 0;
   int ret;
 
   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (i, "tbl_id %d", &tbl_id))
-       tbl_id_set = 1;
-      if (unformat (i, "fib_id %d", &fib_id))
-       fib_id_set = 1;
-      if (unformat (i, "oui %d", &oui))
-       oui_set = 1;
+       ;
+      else if (unformat (i, "vpn_ascii_id %s", &vpn_ascii_id))
+       vss_type = VSS_TYPE_ASCII;
+      else if (unformat (i, "fib_id %d", &fib_id))
+       vss_type = VSS_TYPE_VPN_ID;
+      else if (unformat (i, "oui %d", &oui))
+       vss_type = VSS_TYPE_VPN_ID;
       else if (unformat (i, "ipv6"))
        is_ipv6 = 1;
       else if (unformat (i, "del"))
        is_add = 0;
       else
-       {
-         clib_warning ("parse error '%U'", format_unformat_error, i);
-         return -99;
-       }
+       break;
     }
 
-  if (tbl_id_set == 0)
+  if (tbl_id == ~0)
     {
-      errmsg ("missing tbl id");
+      errmsg ("missing tbl_id ");
+      vec_free (vpn_ascii_id);
       return -99;
     }
 
-  if (fib_id_set == 0)
-    {
-      errmsg ("missing fib id");
-      return -99;
-    }
-  if (oui_set == 0)
+  if ((vpn_ascii_id) && (vec_len (vpn_ascii_id) > 128))
     {
-      errmsg ("missing oui");
+      errmsg ("vpn_ascii_id cannot be longer than 128 ");
+      vec_free (vpn_ascii_id);
       return -99;
     }
 
   M (DHCP_PROXY_SET_VSS, mp);
   mp->tbl_id = ntohl (tbl_id);
-  mp->fib_id = ntohl (fib_id);
+  mp->vss_type = vss_type;
+  if (vpn_ascii_id)
+    {
+      clib_memcpy (mp->vpn_ascii_id, vpn_ascii_id, vec_len (vpn_ascii_id));
+      mp->vpn_ascii_id[vec_len (vpn_ascii_id)] = 0;
+    }
+  mp->vpn_index = ntohl (fib_id);
   mp->oui = ntohl (oui);
   mp->is_ipv6 = is_ipv6;
   mp->is_add = is_add;
 
   S (mp);
   W (ret);
+
+  vec_free (vpn_ascii_id);
   return ret;
 }
 
@@ -22344,7 +22358,7 @@ _(sw_interface_set_l2_bridge,                                           \
   "enable | disable")                                                   \
 _(bridge_domain_set_mac_age, "bd_id <bridge-domain-id> mac-age 0-255")  \
 _(bridge_domain_add_del,                                                \
-  "bd_id <bridge-domain-id> [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [bd-tag <tag>] [del]\n") \
+  "bd_id <bridge-domain-id> [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [bd-tag <text>] [del]\n") \
 _(bridge_domain_dump, "[bd_id <bridge-domain-id>]\n")                   \
 _(l2fib_add_del,                                                        \
   "mac <mac-addr> bd_id <bridge-domain-id> [del] | sw_if <intfc> | sw_if_index <id> [static] [filter] [bvi] [count <nn>]\n") \
@@ -22409,7 +22423,7 @@ _(dhcp_proxy_config,                                                    \
   "svr <v46-address> src <v46-address>\n"                               \
    "rx_vrf_id <nn> server_vrf_id <nn>  [del]")                          \
 _(dhcp_proxy_set_vss,                                                   \
-  "tbl_id <n> fib_id <n> oui <n> [ipv6] [del]")                         \
+  "tbl_id <n> [fib_id <n> oui <n> | vpn_ascii_id <text>] [ipv6] [del]") \
 _(dhcp_proxy_dump, "ip6")                                               \
 _(dhcp_client_config,                                                   \
   "<intfc> | sw_if_index <id> [hostname <name>] [disable_event] [del]") \
index 628b674..19650f5 100644 (file)
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-vl_api_version 1.0.0
+vl_api_version 1.0.1
 
 /** \brief DHCP Proxy config add / del request
     @param client_index - opaque cookie to identify the sender
@@ -42,8 +42,10 @@ autoreply define dhcp_proxy_config
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param tbl_id - table id
-    @param oui - first part of vpn id
-    @param fib_id - second part of vpn id
+    @vss_type - 0: use ASCI vpn_id; 1: use oui/vpn_index; 255: global vpn
+    @vpn_ascii - null terminated ASCII VPN ID up to 128 characters
+    @param oui - first part of rfc2685 vpn id, 3 bytes oui 
+    @param vpn_index - second part of rfc2685 vpn id, 4 bytes vpn index
     @param is_ipv6 - ip6 if non-zero, else ip4
     @param is_add - set vss if non-zero, else delete
 */
@@ -52,8 +54,10 @@ autoreply define dhcp_proxy_set_vss
   u32 client_index;
   u32 context;
   u32 tbl_id;
+  u8 vss_type;
+  u8 vpn_ascii_id[129];
   u32 oui;
-  u32 fib_id;
+  u32 vpn_index;
   u8 is_ipv6;
   u8 is_add;
 };
@@ -128,6 +132,8 @@ manual_endian manual_print define dhcp_proxy_details
   u32 rx_vrf_id;
   u32 vss_oui;
   u32 vss_fib_id;
+  u8 vss_type;
+  u8 vss_vpn_ascii_id[129];
   u8 is_ipv6;
   u8 dhcp_src_address[16];
   u8 count;
index 339a788..cd52be8 100644 (file)
@@ -229,19 +229,19 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
                     }
                 }
               o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
-          }
+           }
 
           fl = vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b0));
           // start write at (option*)o, some packets have padding
           if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes)
-          {
+            {
               next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
               pkts_too_big++;
               goto do_trace;
-          }
+           }
 
           if ((o->option == 0xFF)  && ((u8 *)o <= end))
-          {  
+            {  
               vnet_main_t *vnm = vnet_get_main();   
               u16 old_l0, new_l0;
               ip4_address_t _ia0, * ia0 = &_ia0;
@@ -264,65 +264,53 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
               ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0);
                   
               if (ia0 == 0)
-              {
+                {
                   error0 = DHCP_PROXY_ERROR_NO_INTERFACE_ADDRESS;
                   next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_DROP;
                   pkts_no_interface_address++;
                   goto do_trace;
-              }
+                }
 
               /* Add option 82 */
               o->option = 82;   /* option 82 */
               o->length = 12;   /* 12 octets to follow */
               o->data[0] = 1;   /* suboption 1, circuit ID (=FIB id) */
               o->data[1] = 4;   /* length of suboption */
-              o->data[2] = (original_sw_if_index >> 24) & 0xFF;
-              o->data[3] = (original_sw_if_index >> 16) & 0xFF;
-              o->data[4] = (original_sw_if_index >> 8)  & 0xFF;
-              o->data[5] = (original_sw_if_index >> 0)  & 0xFF;
+             u32 *o_ifid = (u32 *) &o->data[2];
+             *o_ifid = clib_host_to_net_u32 (original_sw_if_index);
               o->data[6] = 5; /* suboption 5 (client RX intfc address) */
               o->data[7] = 4; /* length 4 */
-              o->data[8] = ia0->as_u8[0];
-              o->data[9] = ia0->as_u8[1];
-              o->data[10] = ia0->as_u8[2];
-              o->data[11] = ia0->as_u8[3];
+             u32 *o_addr = (u32 *) &o->data[8];
+             *o_addr = ia0->as_u32;
               o->data[12] = 0xFF;
 
               vss = dhcp_get_vss_info (dpm, fib_index, FIB_PROTOCOL_IP4);
-              if (NULL != vss)
-              {
-                  u32 opt82_fib_id=0, opt82_oui=0;
-
-                  opt82_oui =  vss->oui;
-                  opt82_fib_id =  vss->fib_id;
-
-                  o->data[12] = 151; /* vss suboption */
-                  if (255 == opt82_fib_id) {
-                      o->data[13] = 1;   /* length */
-                      o->data[14] = 255;   /* vss option type */
-                      o->data[15] = 152; /* vss control suboption */
-                      o->data[16] = 0;   /* length */
-                      /* and a new "end-of-options" option (0xff) */
-                      o->data[17] = 0xFF;
-                      o->length += 5;
-                  } else {
-                      o->data[13] = 8;   /* length */
-                      o->data[14] = 1;   /* vss option type */
-                      o->data[15] = (opt82_oui >> 16) & 0xff;
-                      o->data[16] = (opt82_oui >> 8) & 0xff;
-                      o->data[17] = (opt82_oui ) & 0xff;
-                      o->data[18] = (opt82_fib_id >> 24) & 0xff;
-                      o->data[19] = (opt82_fib_id >> 16) & 0xff;
-                      o->data[20] = (opt82_fib_id >> 8) & 0xff;
-                      o->data[21] = (opt82_fib_id) & 0xff;
-                      o->data[22] = 152; /* vss control suboption */
-                      o->data[23] = 0;   /* length */
-                          
-                      /* and a new "end-of-options" option (0xff) */
-                      o->data[24] = 0xFF;
-                      o->length += 12;
-                  }
-              }
+              if (vss)
+                {
+                 u32 id_len;                   /* length of VPN ID */
+
+                 if (vss->vss_type == VSS_TYPE_VPN_ID)
+                   {
+                     id_len = sizeof (vss->vpn_id);    /* vpn_id is 7 bytes */
+                     memcpy (&o->data[15], vss->vpn_id, id_len);
+                   }
+                 else if (vss->vss_type == VSS_TYPE_ASCII)
+                   {
+                     id_len = vec_len (vss->vpn_ascii_id);
+                     memcpy (&o->data[15], vss->vpn_ascii_id, id_len);
+                   }
+                 else  /* must be VSS_TYPE_DEFAULT, no VPN ID */
+                   id_len = 0; 
+
+                  o->data[12] = 151;           /* vss suboption */
+                 o->data[13] = id_len + 1;     /* length: vss_type + id_len */
+                 o->data[14] = vss->vss_type;  /* vss option type */
+                 o->data[15 + id_len] = 152;   /* vss control suboption */
+                 o->data[16 + id_len] = 0;     /* length */
+                 o->data[17 + id_len] = 0xFF;  /* "end-of-options" (0xFF) */
+                 /* 5 bytes for suboption headers 151+len, 152+len and 0xFF */
+                 o->length += id_len + 5; 
+                }
 
               len = o->length + 3;
               b0->current_length += len;
@@ -341,11 +329,13 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
               new_l0 = clib_net_to_host_u16 (u0->length);
               new_l0 += len;
               u0->length = clib_host_to_net_u16 (new_l0);
-          } else {
+            } 
+         else 
+           {
               vlib_node_increment_counter 
                   (vm, dhcp_proxy_to_server_node.index,
                    DHCP_PROXY_ERROR_OPTION_82_ERROR, 1);
-          }
+           }
           
           next0 = DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP;
 
@@ -355,11 +345,11 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
            * those servers
            */
           if (is_discover && vec_len(proxy->dhcp_servers) > 1)
-          {
+            {
               u32 ii;
 
               for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++)
-              {
+                {
                   vlib_buffer_t *c0;
                   u32 ci0;
               
@@ -387,7 +377,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
                                                    ci0, next0);
 
                   if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
-                  {
+                    {
                       dhcp_proxy_trace_t *tr;
 
                       tr = vlib_add_trace (vm, node, c0, sizeof (*tr));
@@ -397,15 +387,15 @@ dhcp_proxy_to_server_input (vlib_main_t * vm,
                       tr->sw_if_index = sw_if_index;
                       if (next0 == DHCP_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
                           tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32;
-                  }
+                   }
 
                   if (PREDICT_FALSE(0 == n_left_to_next))
-                  {
+                    {
                       vlib_put_next_frame (vm, node, next_index,
                                            n_left_to_next);
                       vlib_get_next_frame (vm, node, next_index,
                                            to_next, n_left_to_next);
-                  }
+                    }
               }
           }
         do_trace:
@@ -949,54 +939,47 @@ dhcp_option_82_vss_fn (vlib_main_t * vm,
                         unformat_input_t * input,
                         vlib_cli_command_t * cmd)
 {
-  int is_del = 0, got_new_vpn_id=0;
-  u32 oui=0, fib_id=0, tbl_id=~0;
+  u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT;
+  u32 oui = 0, fib_id = 0, tbl_id = ~0;
+  u8 *vpn_ascii_id = 0;
 
   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) 
     {
-
-      if (unformat(input, "delete") || unformat(input, "del"))
-          is_del = 1;    
+      if (unformat (input, "table %d", &tbl_id))
+         ;
       else if (unformat (input, "oui %d", &oui))
-          got_new_vpn_id = 1;
+         vss_type = VSS_TYPE_VPN_ID;
       else if (unformat (input, "vpn-id %d", &fib_id))
-          got_new_vpn_id = 1;
-      else if (unformat (input, "table %d", &tbl_id))
-          got_new_vpn_id = 1;
+         vss_type = VSS_TYPE_VPN_ID;
+      else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id))
+         vss_type = VSS_TYPE_ASCII;
+      else if (unformat(input, "delete") || unformat(input, "del"))
+         is_del = 1;    
       else
-          break;
-  }
+        break;
+    }
+
   if (tbl_id == ~0)
       return clib_error_return (0, "no table ID specified.");
   
-  if (is_del || got_new_vpn_id)
+  int rv = dhcp_proxy_set_vss (FIB_PROTOCOL_IP4, tbl_id, vss_type, 
+                              vpn_ascii_id, oui, fib_id, is_del);
+  switch (rv)
     {
-      int rv;
-      rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP4, tbl_id, oui, fib_id, is_del);
-      switch (rv)
-        {
-        case 0:
-            return 0;
-            
-        case VNET_API_ERROR_NO_SUCH_FIB:
-            return clib_error_return (0, "option 82 vss(oui:%d, vpn-id:%d) not found in table %d",
-                                      oui, fib_id, tbl_id);
-            
-        case VNET_API_ERROR_NO_SUCH_ENTRY:
-            return clib_error_return (0, "option 82 vss for table %d not found in in pool.",
-                                      tbl_id);
-        default:
-          return clib_error_return (0, "BUG: rv %d", rv);
-        }
+    case 0:
+       return 0;
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+       return clib_error_return (0, "option 82 vss for table %d not found in in pool.",
+                                 tbl_id);
+    default:
+       return clib_error_return (0, "BUG: rv %d", rv);
+
     }
-  else
-      return clib_error_return (0, "parse error`%U'",
-                                format_unformat_error, input);
 }
 
 VLIB_CLI_COMMAND (dhcp_proxy_vss_command,static) = {
   .path = "set dhcp option-82 vss",
-  .short_help = "set dhcp option-82 vss [del] table <table id> oui <oui> vpn-id <vpn-id>",
+  .short_help = "set dhcp option-82 vss [del] table <table id> [oui <n> vpn-id <n> | vpn-ascii-id <text>]",
   .function = dhcp_option_82_vss_fn,
 };
 
index ddcde7a..24a1814 100644 (file)
@@ -164,7 +164,8 @@ typedef CLIB_PACKED (struct {
 
 typedef CLIB_PACKED (struct {
   dhcpv6_option_t opt;
-  u8 data[8];  // data[0]:type, data[1..7]: VPN ID
+  u8 vss_type;
+  u8 data[0];
 }) dhcpv6_vss_t;
 
 typedef CLIB_PACKED (struct {
index ce7a8fc..3cac278 100644 (file)
@@ -330,31 +330,40 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm,
                cmac = (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length);
                b0->current_length += (sizeof (*cmac));
                cmac->opt.length =clib_host_to_net_u16(sizeof(*cmac) -
-                                                      sizeof(cmac->opt));
+                                                     sizeof(cmac->opt));
                cmac->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS);
-               cmac->link_type = clib_host_to_net_u16(1); // ethernet
+               cmac->link_type = clib_host_to_net_u16(1); /* ethernet */
                clib_memcpy(cmac->data, client_src_mac, 6);
                u1->length += sizeof(*cmac);
             }
 
           vss = dhcp_get_vss_info(dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
 
-          if (NULL != vss) {
+          if (vss)
+           {
+             u16 id_len;       /* length of VPN ID */
+             u16 type_len = sizeof (vss1->vss_type);
+
               vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length);
-              b0->current_length += (sizeof (*vss1));
-              vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) -
-                                                    sizeof(vss1->opt));
-              vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS);
-              vss1->data[0] = 1;   // type
-              vss1->data[1] = vss->oui >>16 & 0xff;
-              vss1->data[2] = vss->oui >>8  & 0xff;
-              vss1->data[3] = vss->oui & 0xff;
-              vss1->data[4] = vss->fib_id >> 24 & 0xff;
-              vss1->data[5] = vss->fib_id >> 16 & 0xff;
-              vss1->data[6] = vss->fib_id >> 8 & 0xff;
-              vss1->data[7] = vss->fib_id & 0xff;
-              u1->length += sizeof(*vss1);
-          }
+             vss1->vss_type = vss->vss_type;
+             if (vss->vss_type == VSS_TYPE_VPN_ID)
+               {
+                 id_len = sizeof (vss->vpn_id);        /* vpn_id is 7 bytes */
+                 memcpy (vss1->data, vss->vpn_id, id_len);
+               }
+             else if (vss->vss_type == VSS_TYPE_ASCII)
+               {
+                 id_len = vec_len (vss->vpn_ascii_id);
+                 memcpy (vss1->data, vss->vpn_ascii_id, id_len);
+               }
+             else      /* must be VSS_TYPE_DEFAULT, no VPN ID */
+               id_len = 0;
+
+              vss1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_VSS);
+             vss1->opt.length = clib_host_to_net_u16 (type_len + id_len);
+             u1->length += type_len + id_len + sizeof (vss1->opt);
+             b0->current_length += type_len + id_len + sizeof (vss1->opt);
+            }
 
           pkts_to_server++;
           u1->checksum = 0;
@@ -1030,18 +1039,20 @@ dhcpv6_vss_command_fn (vlib_main_t * vm,
                        unformat_input_t * input,
                        vlib_cli_command_t * cmd)
 {
-  int is_del = 0, got_new_vss=0;
-  u32 oui=0;
-  u32 fib_id=0, tbl_id=~0;
+  u8 is_del = 0, vss_type = VSS_TYPE_DEFAULT;
+  u8 *vpn_ascii_id = 0;
+  u32 oui = 0, fib_id = 0, tbl_id = ~0;
 
   while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "oui %d", &oui))
-          got_new_vss = 1;
+      if (unformat (input, "table %d", &tbl_id))
+          ;
+      else if (unformat (input, "oui %d", &oui))
+         vss_type = VSS_TYPE_VPN_ID;
       else if (unformat (input, "vpn-id %d", &fib_id))
-          got_new_vss = 1;
-      else if (unformat (input, "table %d", &tbl_id))
-          got_new_vss = 1;
+         vss_type = VSS_TYPE_VPN_ID;
+      else if (unformat (input, "vpn-ascii-id %s", &vpn_ascii_id))
+         vss_type = VSS_TYPE_ASCII;
       else if (unformat(input, "delete") || unformat(input, "del"))
           is_del = 1;
       else
@@ -1051,37 +1062,23 @@ dhcpv6_vss_command_fn (vlib_main_t * vm,
   if (tbl_id ==~0)
       return clib_error_return (0, "no table ID specified.");
 
-  if (is_del || got_new_vss)
+  int rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP6, tbl_id, vss_type,
+                             vpn_ascii_id, oui, fib_id, is_del);
+  switch (rv)
     {
-      int rv;
-
-      rv = dhcp_proxy_set_vss(FIB_PROTOCOL_IP6, tbl_id, oui, fib_id, is_del);
-      switch (rv)
-        {
-        case 0:
-          return 0;
-
-        case VNET_API_ERROR_NO_SUCH_FIB:
-            return clib_error_return (0, "vss info (oui:%d, vpn-id:%d)  not found in table %d.",
-                                      oui, fib_id, tbl_id);
-
-        case VNET_API_ERROR_NO_SUCH_ENTRY:
-            return clib_error_return (0, "vss for table %d not found in pool.",
-                                      tbl_id);
-
-        default:
-          return clib_error_return (0, "BUG: rv %d", rv);
-        }
+    case 0:
+       return 0;
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+       return clib_error_return (0, "vss for table %d not found in pool.",
+                                 tbl_id);
+    default:
+       return clib_error_return (0, "BUG: rv %d", rv);
     }
-  else
-      return clib_error_return (0, "parse error`%U'",
-                                format_unformat_error, input);
-
 }
 
 VLIB_CLI_COMMAND (dhcpv6_proxy_vss_command, static) = {
   .path = "set dhcpv6 vss",
-  .short_help = "set dhcpv6 vss table <table-id> oui <oui> vpn-idx <vpn-idx>",
+  .short_help = "set dhcpv6 vss table <table-id> [oui <n> vpn-id <n> | vpn-ascii-id <text>]",
   .function = dhcpv6_vss_command_fn,
 };
 
index d6984f2..ad96e02 100644 (file)
@@ -55,14 +55,16 @@ static void
 vl_api_dhcp_proxy_set_vss_t_handler (vl_api_dhcp_proxy_set_vss_t * mp)
 {
   vl_api_dhcp_proxy_set_vss_reply_t *rmp;
+  u8 *vpn_ascii_id;
   int rv;
 
-  rv = dhcp_proxy_set_vss ((mp->is_ipv6 ?
-                           FIB_PROTOCOL_IP6 :
-                           FIB_PROTOCOL_IP4),
-                          ntohl (mp->tbl_id),
-                          ntohl (mp->oui),
-                          ntohl (mp->fib_id), (int) mp->is_add == 0);
+  mp->vpn_ascii_id[sizeof (mp->vpn_ascii_id) - 1] = 0;
+  vpn_ascii_id = format (0, "%s", mp->vpn_ascii_id);
+  rv =
+    dhcp_proxy_set_vss ((mp->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4),
+                       ntohl (mp->tbl_id), mp->vss_type, vpn_ascii_id,
+                       ntohl (mp->oui), ntohl (mp->vpn_index),
+                       mp->is_add == 0);
 
   REPLY_MACRO (VL_API_DHCP_PROXY_SET_VSS_REPLY);
 }
@@ -147,11 +149,27 @@ dhcp_send_details (fib_protocol_t proto,
 
   vss = dhcp_get_vss_info (&dhcp_proxy_main, proxy->rx_fib_index, proto);
 
-  if (NULL != vss)
+  if (vss)
     {
-      mp->vss_oui = htonl (vss->oui);
-      mp->vss_fib_id = htonl (vss->fib_id);
+      mp->vss_type = vss->vss_type;
+      if (vss->vss_type == VSS_TYPE_ASCII)
+       {
+         u32 id_len = vec_len (vss->vpn_ascii_id);
+         clib_memcpy (mp->vss_vpn_ascii_id, vss->vpn_ascii_id, id_len);
+       }
+      else if (vss->vss_type == VSS_TYPE_VPN_ID)
+       {
+         u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8)
+           + ((u32) vss->vpn_id[2]);
+         u32 fib_id = ((u32) vss->vpn_id[3] << 24) +
+           ((u32) vss->vpn_id[4] << 16) + ((u32) vss->vpn_id[5] << 8) +
+           ((u32) vss->vpn_id[6]);
+         mp->vss_oui = htonl (oui);
+         mp->vss_fib_id = htonl (fib_id);
+       }
     }
+  else
+    mp->vss_type = VSS_TYPE_INVALID;
 
   vec_foreach_index (count, proxy->dhcp_servers)
   {
index 1784906..dae6312 100644 (file)
@@ -278,19 +278,60 @@ dhcp_vss_show_walk (dhcp_vss_t *vss,
 {
     vlib_main_t * vm = ctx;
 
-    vlib_cli_output (vm, "%=6d%=6d%=12d",
-                     rx_table_id,
-                     vss->oui,
-                     vss->fib_id);
+    if (vss->vss_type == VSS_TYPE_VPN_ID)
+      {
+       u32 oui = ((u32) vss->vpn_id[0] << 16) + ((u32) vss->vpn_id[1] << 8)
+           + ((u32) vss->vpn_id[2]);
+       u32 fib_id = ((u32) vss->vpn_id[3] << 24) + ((u32) vss->vpn_id[4] << 16)
+           + ((u32) vss->vpn_id[5] << 8) + ((u32) vss->vpn_id[6]);
+       vlib_cli_output (vm, " fib_table: %d  oui: %d vpn_index: %d",
+                        rx_table_id, oui, fib_id);
+      }
+    else if (vss->vss_type == VSS_TYPE_ASCII)
+       vlib_cli_output (vm, " fib_table: %d  vpn_id: %s",
+                        rx_table_id, vss->vpn_ascii_id);
+    else
+       vlib_cli_output (vm, " fib_table: %d  default global vpn", rx_table_id);
 
     return (1);
 }
 
+void update_vss (dhcp_vss_t *v,
+                u8 vss_type,
+                u8 *vpn_ascii_id,
+                u32 oui,
+                u32 vpn_index)
+{
+  v->vss_type = vss_type;
+  if (v->vpn_ascii_id)
+    {
+       if (v->vpn_ascii_id == (u8 *) ~0)
+       v->vpn_ascii_id = 0;
+      else
+       vec_free (v->vpn_ascii_id);
+    }
+
+  if (vss_type == VSS_TYPE_ASCII)
+      v->vpn_ascii_id = vpn_ascii_id;
+  else if (vss_type == VSS_TYPE_VPN_ID)
+    {
+      v->vpn_id[0] = (oui >> 16) & 0xff;
+      v->vpn_id[1] = (oui >> 8) & 0xff;
+      v->vpn_id[2] = (oui >> 0) & 0xff;
+      v->vpn_id[3] = (vpn_index >> 24) & 0xff;
+      v->vpn_id[4] = (vpn_index >> 16) & 0xff;
+      v->vpn_id[5] = (vpn_index >> 8) & 0xff;
+      v->vpn_id[6] = (vpn_index >> 0) & 0xff;
+    }
+}
+
 int dhcp_proxy_set_vss (fib_protocol_t proto,
                         u32 tbl_id,
+                       u8 vss_type,
+                       u8 *vpn_ascii_id,
                         u32 oui,
-                        u32 fib_id, 
-                        int is_del)
+                        u32 vpn_index,
+                        u8 is_del)
 {
   dhcp_proxy_main_t *dm = &dhcp_proxy_main;
   dhcp_vss_t *v = NULL;
@@ -306,43 +347,40 @@ int dhcp_proxy_set_vss (fib_protocol_t proto,
   v = dhcp_get_vss_info(dm, rx_fib_index, proto);
 
   if (NULL != v)
-  {
+    {
       if (is_del)
-      {
+        {
           /* release the lock held on the table when the VSS
            * info was created */
           dhcp_proxy_rx_table_unlock (proto, rx_fib_index);
 
+         vec_free (v->vpn_ascii_id);
           pool_put (dm->vss[proto], v);
           dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = ~0;
-      }
+        }
       else
-      {
-          /* this is a modify */
-          v->fib_id = fib_id;
-          v->oui = oui;
-      }
-  }
+        {
+         update_vss (v, vss_type, vpn_ascii_id, oui, vpn_index);
+        }
+    }
   else
-  {
+    {
       if (is_del)
-          rc = VNET_API_ERROR_NO_SUCH_ENTRY;
+        rc = VNET_API_ERROR_NO_SUCH_ENTRY;
       else
-      {
+        {
           /* create a new entry */
           vec_validate_init_empty(dm->vss_index_by_rx_fib_index[proto],
                                   rx_fib_index, ~0);
 
           /* hold a lock on the table whilst the VSS info exist */
           pool_get (dm->vss[proto], v);
-          v->fib_id = fib_id;
-          v->oui = oui;
-
+         update_vss (v, vss_type, vpn_ascii_id, oui, vpn_index);
           dm->vss_index_by_rx_fib_index[proto][rx_fib_index] =
               v - dm->vss[proto];
           dhcp_proxy_rx_table_lock (proto, rx_fib_index);
-      }
-  }
+        }
+    }
 
   /* Release the lock taken during the create_or_lock at the start */
   dhcp_proxy_rx_table_unlock (proto, rx_fib_index);
index ef2bc0a..9b15ac8 100644 (file)
@@ -48,13 +48,24 @@ typedef enum {
  */
 typedef struct dhcp_vss_t_ {
     /**
-     * @brief ?? RFC doesn't say
+     * @brief VSS type as defined in RFC 6607:
+     *  0 for NVT ASCII VPN Identifier
+     *   1 for RFC 2685 VPN-ID of 7 octects - 3 bytes OUI & 4 bytes VPN index
+     *   255 for global default VPN
      */
-    u32 oui;
+    u8 vss_type;
+#define VSS_TYPE_ASCII 0
+#define VSS_TYPE_VPN_ID 1
+#define VSS_TYPE_INVALID 123
+#define VSS_TYPE_DEFAULT 255
     /**
-     * @brief VPN-ID
+     * @brief Type 1 VPN-ID
      */
-    u32 fib_id;
+    u8 vpn_id[7];
+    /**
+     * @brief Type 0 ASCII VPN Identifier
+     */
+    u8 *vpn_ascii_id;
 } dhcp_vss_t;
 
 /**
@@ -152,11 +163,13 @@ int dhcp_vss_show_walk (dhcp_vss_t *vss,
 /**
  * @brief Configure/set a new VSS info
  */
-int dhcp_proxy_set_vss(fib_protocol_t proto,
-                       u32 vrf_id,
-                       u32 oui,
-                       u32 fib_id,
-                       int is_del);
+int dhcp_proxy_set_vss (fib_protocol_t proto,
+                        u32 tbl_id,
+                       u8 vss_type,
+                       u8 *vpn_ascii_id,
+                        u32 oui,
+                        u32 vpn_index,
+                       u8 is_del);
 
 /**
  * @brief Dump the proxy configs to the API
index fd0e88a..f27acda 100644 (file)
@@ -844,9 +844,13 @@ static void *vl_api_dhcp_proxy_set_vss_t_print
 
   s = format (s, "tbl_id %d ", ntohl (mp->tbl_id));
 
-  s = format (s, "fib_id %d ", ntohl (mp->fib_id));
-
-  s = format (s, "oui %d ", ntohl (mp->oui));
+  if (mp->vss_type == VSS_TYPE_VPN_ID)
+    {
+      s = format (s, "fib_id %d ", ntohl (mp->vpn_index));
+      s = format (s, "oui %d ", ntohl (mp->oui));
+    }
+  else if (mp->vss_type == VSS_TYPE_ASCII)
+    s = format (s, "vpn_ascii_id %s", mp->vpn_ascii_id);
 
   if (mp->is_ipv6 != 0)
     s = format (s, "ipv6 ");
index 42b80af..7ae98e8 100644 (file)
@@ -4,7 +4,7 @@ import unittest
 import socket
 import struct
 
-from framework import VppTestCase, VppTestRunner
+from framework import VppTestCase, VppTestRunner, running_extended_tests
 from vpp_neighbor import VppNeighbor
 from vpp_ip_route import find_route, VppIpTable
 from util import mk_ll_addr
@@ -33,12 +33,12 @@ class TestDHCP(VppTestCase):
     def setUp(self):
         super(TestDHCP, self).setUp()
 
-        # create 3 pg interfaces
-        self.create_pg_interfaces(range(4))
+        # create 6 pg interfaces for pg0 to pg5
+        self.create_pg_interfaces(range(6))
         self.tables = []
 
-        # pg0 and 1 are IP configured in VRF 0 and 1.
-        # pg2 and 3 are non IP-configured in VRF 0 and 1
+        # pg0 to 2 are IP configured in VRF 0, 1 and 2.
+        # pg3 to 5 are non IP-configured in VRF 0, 1 and 2.
         table_id = 0
         for table_id in range(1, 4):
             tbl4 = VppIpTable(self, table_id)
@@ -49,7 +49,7 @@ class TestDHCP(VppTestCase):
             self.tables.append(tbl6)
 
         table_id = 0
-        for i in self.pg_interfaces[:2]:
+        for i in self.pg_interfaces[:3]:
             i.admin_up()
             i.set_table_ip4(table_id)
             i.set_table_ip6(table_id)
@@ -60,14 +60,14 @@ class TestDHCP(VppTestCase):
             table_id += 1
 
         table_id = 0
-        for i in self.pg_interfaces[2:]:
+        for i in self.pg_interfaces[3:]:
             i.admin_up()
             i.set_table_ip4(table_id)
             i.set_table_ip6(table_id)
             table_id += 1
 
     def tearDown(self):
-        for i in self.pg_interfaces[:2]:
+        for i in self.pg_interfaces[:3]:
             i.unconfig_ip4()
             i.unconfig_ip6()
 
@@ -96,10 +96,11 @@ class TestDHCP(VppTestCase):
 
         self.assertTrue(found)
 
-    def validate_relay_options(self, pkt, intf, ip_addr, fib_id, oui):
+    def validate_relay_options(self, pkt, intf, ip_addr, vpn_id, fib_id, oui):
         dhcp = pkt[DHCP]
         found = 0
         data = []
+        id_len = len(vpn_id)
 
         for i in dhcp.options:
             if type(i) is tuple:
@@ -110,6 +111,8 @@ class TestDHCP(VppTestCase):
                     data = i[1]
                     if oui != 0:
                         self.assertEqual(len(data), 24)
+                    elif len(vpn_id) > 0:
+                        self.assertEqual(len(data), len(vpn_id)+17)
                     else:
                         self.assertEqual(len(data), 12)
 
@@ -142,8 +145,9 @@ class TestDHCP(VppTestCase):
                     self.assertEqual(data[11], claddr[3])
 
                     if oui != 0:
-                        # sub-option 151 encodes the 3 byte oui
-                        # and the 4 byte fib_id
+                        # sub-option 151 encodes vss_type 1,
+                        # the 3 byte oui and the 4 byte fib_id
+                        self.assertEqual(id_len, 0)
                         self.assertEqual(ord(data[12]), 151)
                         self.assertEqual(ord(data[13]), 8)
                         self.assertEqual(ord(data[14]), 1)
@@ -159,6 +163,19 @@ class TestDHCP(VppTestCase):
                         self.assertEqual(ord(data[22]), 152)
                         self.assertEqual(ord(data[23]), 0)
 
+                    if id_len > 0:
+                        # sub-option 151 encode vss_type of 0
+                        # followerd by vpn_id in ascii
+                        self.assertEqual(oui, 0)
+                        self.assertEqual(ord(data[12]), 151)
+                        self.assertEqual(ord(data[13]), id_len+1)
+                        self.assertEqual(ord(data[14]), 0)
+                        self.assertEqual(data[15:15+id_len], vpn_id)
+
+                        # VSS control sub-option
+                        self.assertEqual(ord(data[15+len(vpn_id)]), 152)
+                        self.assertEqual(ord(data[16+len(vpn_id)]), 0)
+
                     found = 1
         self.assertTrue(found)
 
@@ -174,7 +191,7 @@ class TestDHCP(VppTestCase):
                     found = True
         self.assertTrue(found)
 
-    def verify_dhcp_offer(self, pkt, intf, fib_id=0, oui=0):
+    def verify_dhcp_offer(self, pkt, intf, vpn_id="", fib_id=0, oui=0):
         ether = pkt[Ether]
         self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
         self.assertEqual(ether.src, intf.local_mac)
@@ -189,7 +206,7 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp_msg_type(pkt, "offer")
         data = self.validate_relay_options(pkt, intf, intf.local_ip4,
-                                           fib_id, oui)
+                                           vpn_id, fib_id, oui)
 
     def verify_orig_dhcp_pkt(self, pkt, intf):
         ether = pkt[Ether]
@@ -229,6 +246,7 @@ class TestDHCP(VppTestCase):
 
     def verify_relayed_dhcp_discover(self, pkt, intf, src_intf=None,
                                      fib_id=0, oui=0,
+                                     vpn_id="",
                                      dst_mac=None, dst_ip=None):
         if not dst_mac:
             dst_mac = intf.remote_mac
@@ -259,11 +277,13 @@ class TestDHCP(VppTestCase):
 
         data = self.validate_relay_options(pkt, src_intf,
                                            src_intf.local_ip4,
+                                           vpn_id,
                                            fib_id, oui)
         return data
 
     def verify_dhcp6_solicit(self, pkt, intf,
                              peer_ip, peer_mac,
+                             vpn_id="",
                              fib_id=0,
                              oui=0,
                              dst_mac=None,
@@ -293,7 +313,10 @@ class TestDHCP(VppTestCase):
         self.assertEqual(cll.lltype, 1)
         self.assertEqual(cll.clladdr, peer_mac)
 
+        id_len = len(vpn_id)
+
         if fib_id != 0:
+            self.assertEqual(id_len, 0)
             vss = pkt[DHCP6OptVSS]
             self.assertEqual(vss.optlen, 8)
             self.assertEqual(vss.type, 1)
@@ -307,6 +330,13 @@ class TestDHCP(VppTestCase):
             self.assertEqual(ord(vss.data[5]), 0)
             self.assertEqual(ord(vss.data[6]), fib_id)
 
+        if id_len > 0:
+            self.assertEqual(oui, 0)
+            vss = pkt[DHCP6OptVSS]
+            self.assertEqual(vss.optlen, id_len+1)
+            self.assertEqual(vss.type, 0)
+            self.assertEqual(vss.data[0:id_len], vpn_id)
+
         # the relay message should be an encoded Solicit
         msg = pkt[DHCP6OptRelayMsg]
         sol = DHCP6_Solicit()
@@ -336,7 +366,7 @@ class TestDHCP(VppTestCase):
         # Verify no response to DHCP request without DHCP config
         #
         p_disc_vrf0 = (Ether(dst="ff:ff:ff:ff:ff:ff",
-                             src=self.pg2.remote_mac) /
+                             src=self.pg3.remote_mac) /
                        IP(src="0.0.0.0", dst="255.255.255.255") /
                        UDP(sport=DHCP4_CLIENT_PORT,
                            dport=DHCP4_SERVER_PORT) /
@@ -344,17 +374,27 @@ class TestDHCP(VppTestCase):
                        DHCP(options=[('message-type', 'discover'), ('end')]))
         pkts_disc_vrf0 = [p_disc_vrf0]
         p_disc_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
-                             src=self.pg3.remote_mac) /
+                             src=self.pg4.remote_mac) /
+                       IP(src="0.0.0.0", dst="255.255.255.255") /
+                       UDP(sport=DHCP4_CLIENT_PORT,
+                           dport=DHCP4_SERVER_PORT) /
+                       BOOTP(op=1) /
+                       DHCP(options=[('message-type', 'discover'), ('end')]))
+        pkts_disc_vrf1 = [p_disc_vrf1]
+        p_disc_vrf2 = (Ether(dst="ff:ff:ff:ff:ff:ff",
+                             src=self.pg5.remote_mac) /
                        IP(src="0.0.0.0", dst="255.255.255.255") /
                        UDP(sport=DHCP4_CLIENT_PORT,
                            dport=DHCP4_SERVER_PORT) /
                        BOOTP(op=1) /
                        DHCP(options=[('message-type', 'discover'), ('end')]))
-        pkts_disc_vrf1 = [p_disc_vrf0]
+        pkts_disc_vrf2 = [p_disc_vrf2]
 
-        self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
+        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
                                         "DHCP with no configuration")
-        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
+        self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
+                                        "DHCP with no configuration")
+        self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2,
                                         "DHCP with no configuration")
 
         #
@@ -371,7 +411,7 @@ class TestDHCP(VppTestCase):
         # Discover packets from the client are dropped because there is no
         # IP address configured on the client facing interface
         #
-        self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
+        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
                                         "Discover DHCP no relay address")
 
         #
@@ -386,13 +426,13 @@ class TestDHCP(VppTestCase):
              DHCP(options=[('message-type', 'offer'), ('end')]))
         pkts = [p]
 
-        self.send_and_assert_no_replies(self.pg2, pkts,
+        self.send_and_assert_no_replies(self.pg3, pkts,
                                         "Offer DHCP no relay address")
 
         #
         # configure an IP address on the client facing interface
         #
-        self.pg2.config_ip4()
+        self.pg3.config_ip4()
 
         #
         # Try again with a discover packet
@@ -401,7 +441,7 @@ class TestDHCP(VppTestCase):
         # UDP source ports are unchanged
         # we've no option 82 config so that should be absent
         #
-        self.pg2.add_stream(pkts_disc_vrf0)
+        self.pg3.add_stream(pkts_disc_vrf0)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -409,7 +449,7 @@ class TestDHCP(VppTestCase):
         rx = rx[0]
 
         option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0,
-                                                      src_intf=self.pg2)
+                                                      src_intf=self.pg3)
 
         #
         # Create an DHCP offer reply from the server with a correctly formatted
@@ -429,10 +469,10 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg2.get_capture(1)
+        rx = self.pg3.get_capture(1)
         rx = rx[0]
 
-        self.verify_dhcp_offer(rx, self.pg2)
+        self.verify_dhcp_offer(rx, self.pg3)
 
         #
         # Bogus Option 82:
@@ -469,7 +509,7 @@ class TestDHCP(VppTestCase):
         #
         # Send a DHCP request in VRF 1. should be dropped.
         #
-        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
+        self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
                                         "DHCP with no configuration VRF 1")
 
         #
@@ -481,65 +521,91 @@ class TestDHCP(VppTestCase):
                                     rx_table_id=0,
                                     is_add=0)
 
-        self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
+        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
                                         "DHCP config removed VRF 0")
-        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
+        self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
                                         "DHCP config removed VRF 1")
 
         #
-        # Add DHCP config for VRF 1
+        # Add DHCP config for VRF 1 & 2
         #
-        server_addr = self.pg1.remote_ip4n
-        src_addr = self.pg1.local_ip4n
-        self.vapi.dhcp_proxy_config(server_addr,
-                                    src_addr,
+        server_addr1 = self.pg1.remote_ip4n
+        src_addr1 = self.pg1.local_ip4n
+        self.vapi.dhcp_proxy_config(server_addr1,
+                                    src_addr1,
                                     rx_table_id=1,
                                     server_table_id=1)
+        server_addr2 = self.pg2.remote_ip4n
+        src_addr2 = self.pg2.local_ip4n
+        self.vapi.dhcp_proxy_config(server_addr2,
+                                    src_addr2,
+                                    rx_table_id=2,
+                                    server_table_id=2)
 
         #
-        # Confim DHCP requests ok in VRF 1.
+        # Confim DHCP requests ok in VRF 1 & 2.
         #  - dropped on IP config on client interface
         #
-        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
+        self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
                                         "DHCP config removed VRF 1")
+        self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2,
+                                        "DHCP config removed VRF 2")
 
         #
         # configure an IP address on the client facing interface
         #
-        self.pg3.config_ip4()
-
-        self.pg3.add_stream(pkts_disc_vrf1)
+        self.pg4.config_ip4()
+        self.pg4.add_stream(pkts_disc_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-
         rx = self.pg1.get_capture(1)
         rx = rx[0]
-        self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3)
+        self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4)
+
+        self.pg5.config_ip4()
+        self.pg5.add_stream(pkts_disc_vrf2)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg2.get_capture(1)
+        rx = rx[0]
+        self.verify_relayed_dhcp_discover(rx, self.pg2, src_intf=self.pg5)
 
         #
         # Add VSS config
-        #  table=1, fib=id=1, oui=4
-        self.vapi.dhcp_proxy_set_vss(1, 1, 4)
+        #  table=1, vss_type=1, vpn_index=1, oui=4
+        #  table=2, vss_type=0, vpn_id = "ip4-table-2"
+        self.vapi.dhcp_proxy_set_vss(1, 1, vpn_index=1, oui=4, is_add=1)
+        self.vapi.dhcp_proxy_set_vss(2, 0, "ip4-table-2", is_add=1)
 
-        self.pg3.add_stream(pkts_disc_vrf1)
+        self.pg4.add_stream(pkts_disc_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
         rx = self.pg1.get_capture(1)
         rx = rx[0]
         self.verify_relayed_dhcp_discover(rx, self.pg1,
-                                          src_intf=self.pg3,
+                                          src_intf=self.pg4,
                                           fib_id=1, oui=4)
 
+        self.pg5.add_stream(pkts_disc_vrf2)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        rx = self.pg2.get_capture(1)
+        rx = rx[0]
+        self.verify_relayed_dhcp_discover(rx, self.pg2,
+                                          src_intf=self.pg5,
+                                          vpn_id="ip4-table-2")
+
         #
         # Add a second DHCP server in VRF 1
         #  expect clients messages to be relay to both configured servers
         #
         self.pg1.generate_remote_hosts(2)
-        server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4)
+        server_addr12 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4)
 
-        self.vapi.dhcp_proxy_config(server_addr2,
-                                    src_addr,
+        self.vapi.dhcp_proxy_config(server_addr12,
+                                    src_addr1,
                                     rx_table_id=1,
                                     server_table_id=1,
                                     is_add=1)
@@ -558,7 +624,7 @@ class TestDHCP(VppTestCase):
         # The frist packet is sent to the second server
         # We're not enforcing that here, it's just the way it is.
         #
-        self.pg3.add_stream(pkts_disc_vrf1)
+        self.pg4.add_stream(pkts_disc_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -566,12 +632,12 @@ class TestDHCP(VppTestCase):
 
         option_82 = self.verify_relayed_dhcp_discover(
             rx[0], self.pg1,
-            src_intf=self.pg3,
+            src_intf=self.pg4,
             dst_mac=self.pg1.remote_hosts[1].mac,
             dst_ip=self.pg1.remote_hosts[1].ip4,
             fib_id=1, oui=4)
         self.verify_relayed_dhcp_discover(rx[1], self.pg1,
-                                          src_intf=self.pg3,
+                                          src_intf=self.pg4,
                                           fib_id=1, oui=4)
 
         #
@@ -597,10 +663,10 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg3.get_capture(2)
+        rx = self.pg4.get_capture(2)
 
-        self.verify_dhcp_offer(rx[0], self.pg3, fib_id=1, oui=4)
-        self.verify_dhcp_offer(rx[1], self.pg3, fib_id=1, oui=4)
+        self.verify_dhcp_offer(rx[0], self.pg4, fib_id=1, oui=4)
+        self.verify_dhcp_offer(rx[1], self.pg4, fib_id=1, oui=4)
 
         #
         # Ensure offers from non-servers are dropeed
@@ -619,7 +685,7 @@ class TestDHCP(VppTestCase):
         # Ensure only the discover is sent to multiple servers
         #
         p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
-                            src=self.pg3.remote_mac) /
+                            src=self.pg4.remote_mac) /
                       IP(src="0.0.0.0", dst="255.255.255.255") /
                       UDP(sport=DHCP4_CLIENT_PORT,
                           dport=DHCP4_SERVER_PORT) /
@@ -627,7 +693,7 @@ class TestDHCP(VppTestCase):
                       DHCP(options=[('message-type', 'request'),
                                     ('end')]))
 
-        self.pg3.add_stream(p_req_vrf1)
+        self.pg4.add_stream(p_req_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -636,8 +702,8 @@ class TestDHCP(VppTestCase):
         #
         # Remove the second DHCP server
         #
-        self.vapi.dhcp_proxy_config(server_addr2,
-                                    src_addr,
+        self.vapi.dhcp_proxy_config(server_addr12,
+                                    src_addr1,
                                     rx_table_id=1,
                                     server_table_id=1,
                                     is_add=0)
@@ -645,45 +711,55 @@ class TestDHCP(VppTestCase):
         #
         # Test we can still relay with the first
         #
-        self.pg3.add_stream(pkts_disc_vrf1)
+        self.pg4.add_stream(pkts_disc_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
         rx = self.pg1.get_capture(1)
         rx = rx[0]
         self.verify_relayed_dhcp_discover(rx, self.pg1,
-                                          src_intf=self.pg3,
+                                          src_intf=self.pg4,
                                           fib_id=1, oui=4)
 
         #
         # Remove the VSS config
         #  relayed DHCP has default vlaues in the option.
         #
-        self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_add=0)
+        self.vapi.dhcp_proxy_set_vss(1, is_add=0)
+        self.vapi.dhcp_proxy_set_vss(2, is_add=0)
 
-        self.pg3.add_stream(pkts_disc_vrf1)
+        self.pg4.add_stream(pkts_disc_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
         rx = self.pg1.get_capture(1)
         rx = rx[0]
-        self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3)
+        self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg4)
 
         #
         # remove DHCP config to cleanup
         #
-        self.vapi.dhcp_proxy_config(server_addr,
-                                    src_addr,
+        self.vapi.dhcp_proxy_config(server_addr1,
+                                    src_addr1,
                                     rx_table_id=1,
                                     server_table_id=1,
                                     is_add=0)
+        self.vapi.dhcp_proxy_config(server_addr2,
+                                    src_addr2,
+                                    rx_table_id=2,
+                                    server_table_id=2,
+                                    is_add=0)
 
-        self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0,
+        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf0,
                                         "DHCP cleanup VRF 0")
-        self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1,
+        self.send_and_assert_no_replies(self.pg4, pkts_disc_vrf1,
                                         "DHCP cleanup VRF 1")
-        self.pg2.unconfig_ip4()
+        self.send_and_assert_no_replies(self.pg5, pkts_disc_vrf2,
+                                        "DHCP cleanup VRF 2")
+
         self.pg3.unconfig_ip4()
+        self.pg4.unconfig_ip4()
+        self.pg5.unconfig_ip4()
 
     def test_dhcp6_proxy(self):
         """ DHCPv6 Proxy"""
@@ -691,30 +767,41 @@ class TestDHCP(VppTestCase):
         # Verify no response to DHCP request without DHCP config
         #
         dhcp_solicit_dst = "ff02::1:2"
-        dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg2.remote_mac)
-        dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg3.remote_mac)
+        dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg3.remote_mac)
+        dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg4.remote_mac)
+        dhcp_solicit_src_vrf2 = mk_ll_addr(self.pg5.remote_mac)
         server_addr_vrf0 = self.pg0.remote_ip6n
         src_addr_vrf0 = self.pg0.local_ip6n
         server_addr_vrf1 = self.pg1.remote_ip6n
         src_addr_vrf1 = self.pg1.local_ip6n
+        server_addr_vrf2 = self.pg2.remote_ip6n
+        src_addr_vrf2 = self.pg2.local_ip6n
 
         dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst))
-        p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg2.remote_mac) /
+        p_solicit_vrf0 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
                           IPv6(src=dhcp_solicit_src_vrf0,
                                dst=dhcp_solicit_dst) /
                           UDP(sport=DHCP6_SERVER_PORT,
                               dport=DHCP6_CLIENT_PORT) /
                           DHCP6_Solicit())
-        p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
+        p_solicit_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) /
                           IPv6(src=dhcp_solicit_src_vrf1,
                                dst=dhcp_solicit_dst) /
                           UDP(sport=DHCP6_SERVER_PORT,
                               dport=DHCP6_CLIENT_PORT) /
                           DHCP6_Solicit())
+        p_solicit_vrf2 = (Ether(dst=dmac, src=self.pg5.remote_mac) /
+                          IPv6(src=dhcp_solicit_src_vrf2,
+                               dst=dhcp_solicit_dst) /
+                          UDP(sport=DHCP6_SERVER_PORT,
+                              dport=DHCP6_CLIENT_PORT) /
+                          DHCP6_Solicit())
 
-        self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0,
+        self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0,
+                                        "DHCP with no configuration")
+        self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1,
                                         "DHCP with no configuration")
-        self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1,
+        self.send_and_assert_no_replies(self.pg5, p_solicit_vrf2,
                                         "DHCP with no configuration")
 
         #
@@ -728,20 +815,20 @@ class TestDHCP(VppTestCase):
                                     server_table_id=0,
                                     is_ipv6=1)
 
-        self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0,
+        self.send_and_assert_no_replies(self.pg3, p_solicit_vrf0,
                                         "DHCP with no configuration")
-        self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1,
+        self.send_and_assert_no_replies(self.pg4, p_solicit_vrf1,
                                         "DHCP with no configuration")
 
         #
         # configure an IP address on the client facing interface
         #
-        self.pg2.config_ip6()
+        self.pg3.config_ip6()
 
         #
         # Now the DHCP requests are relayed to the server
         #
-        self.pg2.add_stream(p_solicit_vrf0)
+        self.pg3.add_stream(p_solicit_vrf0)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -749,7 +836,7 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp6_solicit(rx[0], self.pg0,
                                   dhcp_solicit_src_vrf0,
-                                  self.pg2.remote_mac)
+                                  self.pg3.remote_mac)
 
         #
         # Exception cases for rejected relay responses
@@ -760,7 +847,7 @@ class TestDHCP(VppTestCase):
                       IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
                       UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
                       DHCP6_Advertise())
-        self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
+        self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
                                         "DHCP6 not a relay reply")
 
         # 2 - no relay message option
@@ -769,7 +856,7 @@ class TestDHCP(VppTestCase):
                       UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
                       DHCP6_RelayReply() /
                       DHCP6_Advertise())
-        self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
+        self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
                                         "DHCP not a relay message")
 
         # 3 - no circuit ID
@@ -779,7 +866,7 @@ class TestDHCP(VppTestCase):
                       DHCP6_RelayReply() /
                       DHCP6OptRelayMsg(optlen=0) /
                       DHCP6_Advertise())
-        self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
+        self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
                                         "DHCP6 no circuit ID")
         # 4 - wrong circuit ID
         p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
@@ -789,7 +876,7 @@ class TestDHCP(VppTestCase):
                       DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
                       DHCP6OptRelayMsg(optlen=0) /
                       DHCP6_Advertise())
-        self.send_and_assert_no_replies(self.pg2, p_adv_vrf0,
+        self.send_and_assert_no_replies(self.pg3, p_adv_vrf0,
                                         "DHCP6 wrong circuit ID")
 
         #
@@ -799,7 +886,7 @@ class TestDHCP(VppTestCase):
                       IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
                       UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
                       DHCP6_RelayReply() /
-                      DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') /
+                      DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
                       DHCP6OptRelayMsg(optlen=0) /
                       DHCP6_Advertise(trid=1) /
                       DHCP6OptStatusCode(statuscode=0))
@@ -809,9 +896,9 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg2.get_capture(1)
+        rx = self.pg3.get_capture(1)
 
-        self.verify_dhcp6_advert(rx[0], self.pg2, "::")
+        self.verify_dhcp6_advert(rx[0], self.pg3, "::")
 
         #
         # Send the relay response (the advertisement)
@@ -820,7 +907,7 @@ class TestDHCP(VppTestCase):
                       IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
                       UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
                       DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) /
-                      DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') /
+                      DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
                       DHCP6OptRelayMsg(optlen=0) /
                       DHCP6_Advertise(trid=1) /
                       DHCP6OptStatusCode(statuscode=0))
@@ -830,24 +917,31 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg2.get_capture(1)
+        rx = self.pg3.get_capture(1)
 
-        self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0)
+        self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf0)
 
         #
-        # Add all the config for VRF 1
+        # Add all the config for VRF 1 & 2
         #
         self.vapi.dhcp_proxy_config(server_addr_vrf1,
                                     src_addr_vrf1,
                                     rx_table_id=1,
                                     server_table_id=1,
                                     is_ipv6=1)
-        self.pg3.config_ip6()
+        self.pg4.config_ip6()
+
+        self.vapi.dhcp_proxy_config(server_addr_vrf2,
+                                    src_addr_vrf2,
+                                    rx_table_id=2,
+                                    server_table_id=2,
+                                    is_ipv6=1)
+        self.pg5.config_ip6()
 
         #
         # VRF 1 solicit
         #
-        self.pg3.add_stream(p_solicit_vrf1)
+        self.pg4.add_stream(p_solicit_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -855,7 +949,20 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp6_solicit(rx[0], self.pg1,
                                   dhcp_solicit_src_vrf1,
-                                  self.pg3.remote_mac)
+                                  self.pg4.remote_mac)
+
+        #
+        # VRF 2 solicit
+        #
+        self.pg5.add_stream(p_solicit_vrf2)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        rx = self.pg2.get_capture(1)
+
+        self.verify_dhcp6_solicit(rx[0], self.pg2,
+                                  dhcp_solicit_src_vrf2,
+                                  self.pg5.remote_mac)
 
         #
         # VRF 1 Advert
@@ -864,7 +971,7 @@ class TestDHCP(VppTestCase):
                       IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) /
                       UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
                       DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
-                      DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+                      DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
                       DHCP6OptRelayMsg(optlen=0) /
                       DHCP6_Advertise(trid=1) /
                       DHCP6OptStatusCode(statuscode=0))
@@ -874,16 +981,18 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg3.get_capture(1)
+        rx = self.pg4.get_capture(1)
 
-        self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1)
+        self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1)
 
         #
         # Add VSS config
-        #  table=1, fib=id=1, oui=4
-        self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1)
+        #  table=1, vss_type=1, vpn_index=1, oui=4
+        #  table=2, vss_type=0, vpn_id = "ip6-table-2"
+        self.vapi.dhcp_proxy_set_vss(1, 1, oui=4, vpn_index=1, is_ip6=1)
+        self.vapi.dhcp_proxy_set_vss(2, 0, "IPv6-table-2", is_ip6=1)
 
-        self.pg3.add_stream(p_solicit_vrf1)
+        self.pg4.add_stream(p_solicit_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -891,17 +1000,28 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp6_solicit(rx[0], self.pg1,
                                   dhcp_solicit_src_vrf1,
-                                  self.pg3.remote_mac,
+                                  self.pg4.remote_mac,
                                   fib_id=1,
                                   oui=4)
 
+        self.pg5.add_stream(p_solicit_vrf2)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        rx = self.pg2.get_capture(1)
+
+        self.verify_dhcp6_solicit(rx[0], self.pg2,
+                                  dhcp_solicit_src_vrf2,
+                                  self.pg5.remote_mac,
+                                  vpn_id="IPv6-table-2")
+
         #
         # Remove the VSS config
         #  relayed DHCP has default vlaues in the option.
         #
-        self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0)
+        self.vapi.dhcp_proxy_set_vss(1, is_ip6=1, is_add=0)
 
-        self.pg3.add_stream(p_solicit_vrf1)
+        self.pg4.add_stream(p_solicit_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -909,16 +1029,17 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp6_solicit(rx[0], self.pg1,
                                   dhcp_solicit_src_vrf1,
-                                  self.pg3.remote_mac)
+                                  self.pg4.remote_mac)
 
         #
         # Add a second DHCP server in VRF 1
         #  expect clients messages to be relay to both configured servers
         #
         self.pg1.generate_remote_hosts(2)
-        server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6)
+        server_addr12 = socket.inet_pton(AF_INET6,
+                                         self.pg1.remote_hosts[1].ip6)
 
-        self.vapi.dhcp_proxy_config(server_addr2,
+        self.vapi.dhcp_proxy_config(server_addr12,
                                     src_addr_vrf1,
                                     rx_table_id=1,
                                     server_table_id=1,
@@ -939,7 +1060,7 @@ class TestDHCP(VppTestCase):
         # The frist packet is sent to the second server
         # We're not enforcing that here, it's just the way it is.
         #
-        self.pg3.add_stream(p_solicit_vrf1)
+        self.pg4.add_stream(p_solicit_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -947,10 +1068,10 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp6_solicit(rx[0], self.pg1,
                                   dhcp_solicit_src_vrf1,
-                                  self.pg3.remote_mac)
+                                  self.pg4.remote_mac)
         self.verify_dhcp6_solicit(rx[1], self.pg1,
                                   dhcp_solicit_src_vrf1,
-                                  self.pg3.remote_mac,
+                                  self.pg4.remote_mac,
                                   dst_mac=self.pg1.remote_hosts[1].mac,
                                   dst_ip=self.pg1.remote_hosts[1].ip6)
 
@@ -961,7 +1082,7 @@ class TestDHCP(VppTestCase):
               IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) /
               UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
               DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
-              DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+              DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
               DHCP6OptRelayMsg(optlen=0) /
               DHCP6_Advertise(trid=1) /
               DHCP6OptStatusCode(statuscode=0))
@@ -969,7 +1090,7 @@ class TestDHCP(VppTestCase):
               IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) /
               UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
               DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
-              DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+              DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
               DHCP6OptRelayMsg(optlen=0) /
               DHCP6_Advertise(trid=1) /
               DHCP6OptStatusCode(statuscode=0))
@@ -980,22 +1101,22 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg3.get_capture(2)
+        rx = self.pg4.get_capture(2)
 
-        self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1)
-        self.verify_dhcp6_advert(rx[1], self.pg3, dhcp_solicit_src_vrf1)
+        self.verify_dhcp6_advert(rx[0], self.pg4, dhcp_solicit_src_vrf1)
+        self.verify_dhcp6_advert(rx[1], self.pg4, dhcp_solicit_src_vrf1)
 
         #
         # Ensure only solicit messages are duplicated
         #
-        p_request_vrf1 = (Ether(dst=dmac, src=self.pg3.remote_mac) /
+        p_request_vrf1 = (Ether(dst=dmac, src=self.pg4.remote_mac) /
                           IPv6(src=dhcp_solicit_src_vrf1,
                                dst=dhcp_solicit_dst) /
                           UDP(sport=DHCP6_SERVER_PORT,
                               dport=DHCP6_CLIENT_PORT) /
                           DHCP6_Request())
 
-        self.pg3.add_stream(p_request_vrf1)
+        self.pg4.add_stream(p_request_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -1009,7 +1130,7 @@ class TestDHCP(VppTestCase):
               IPv6(dst=self.pg1.local_ip6, src="3001::1") /
               UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) /
               DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) /
-              DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') /
+              DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') /
               DHCP6OptRelayMsg(optlen=0) /
               DHCP6_Advertise(trid=1) /
               DHCP6OptStatusCode(statuscode=0))
@@ -1019,7 +1140,7 @@ class TestDHCP(VppTestCase):
         #
         # Remove the second DHCP server
         #
-        self.vapi.dhcp_proxy_config(server_addr2,
+        self.vapi.dhcp_proxy_config(server_addr12,
                                     src_addr_vrf1,
                                     rx_table_id=1,
                                     server_table_id=1,
@@ -1029,7 +1150,7 @@ class TestDHCP(VppTestCase):
         #
         # Test we can still relay with the first
         #
-        self.pg3.add_stream(p_solicit_vrf1)
+        self.pg4.add_stream(p_solicit_vrf1)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -1037,11 +1158,17 @@ class TestDHCP(VppTestCase):
 
         self.verify_dhcp6_solicit(rx[0], self.pg1,
                                   dhcp_solicit_src_vrf1,
-                                  self.pg3.remote_mac)
+                                  self.pg4.remote_mac)
 
         #
         # Cleanup
         #
+        self.vapi.dhcp_proxy_config(server_addr_vrf2,
+                                    src_addr_vrf2,
+                                    rx_table_id=2,
+                                    server_table_id=2,
+                                    is_ipv6=1,
+                                    is_add=0)
         self.vapi.dhcp_proxy_config(server_addr_vrf1,
                                     src_addr_vrf1,
                                     rx_table_id=1,
@@ -1062,8 +1189,9 @@ class TestDHCP(VppTestCase):
                                     server_table_id=0,
                                     is_ipv6=1,
                                     is_add=0)
-        self.pg2.unconfig_ip6()
         self.pg3.unconfig_ip6()
+        self.pg4.unconfig_ip6()
+        self.pg5.unconfig_ip6()
 
     def test_dhcp_client(self):
         """ DHCP Client"""
@@ -1073,119 +1201,119 @@ class TestDHCP(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
 
         #
-        # Configure DHCP client on PG2 and capture the discover sent
+        # Configure DHCP client on PG3 and capture the discover sent
         #
-        self.vapi.dhcp_client(self.pg2.sw_if_index, hostname)
+        self.vapi.dhcp_client(self.pg3.sw_if_index, hostname)
 
-        rx = self.pg2.get_capture(1)
+        rx = self.pg3.get_capture(1)
 
-        self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname)
+        self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname)
 
         #
-        # Sned back on offer, expect the request
+        # Send back on offer, expect the request
         #
-        p_offer = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) /
-                   IP(src=self.pg2.remote_ip4, dst="255.255.255.255") /
+        p_offer = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
+                   IP(src=self.pg3.remote_ip4, dst="255.255.255.255") /
                    UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
-                   BOOTP(op=1, yiaddr=self.pg2.local_ip4) /
+                   BOOTP(op=1, yiaddr=self.pg3.local_ip4) /
                    DHCP(options=[('message-type', 'offer'),
-                                 ('server_id', self.pg2.remote_ip4),
+                                 ('server_id', self.pg3.remote_ip4),
                                  ('end')]))
 
-        self.pg2.add_stream(p_offer)
+        self.pg3.add_stream(p_offer)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg2.get_capture(1)
-        self.verify_orig_dhcp_request(rx[0], self.pg2, hostname,
-                                      self.pg2.local_ip4)
+        rx = self.pg3.get_capture(1)
+        self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
+                                      self.pg3.local_ip4)
 
         #
         # Send an acknowloedgement
         #
-        p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) /
-                 IP(src=self.pg2.remote_ip4, dst="255.255.255.255") /
+        p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
+                 IP(src=self.pg3.remote_ip4, dst="255.255.255.255") /
                  UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
-                 BOOTP(op=1, yiaddr=self.pg2.local_ip4) /
+                 BOOTP(op=1, yiaddr=self.pg3.local_ip4) /
                  DHCP(options=[('message-type', 'ack'),
                                ('subnet_mask', "255.255.255.0"),
-                               ('router', self.pg2.remote_ip4),
-                               ('server_id', self.pg2.remote_ip4),
+                               ('router', self.pg3.remote_ip4),
+                               ('server_id', self.pg3.remote_ip4),
                                ('lease_time', 43200),
                                ('end')]))
 
-        self.pg2.add_stream(p_ack)
+        self.pg3.add_stream(p_ack)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
         #
         # We'll get an ARP request for the router address
         #
-        rx = self.pg2.get_capture(1)
+        rx = self.pg3.get_capture(1)
 
-        self.assertEqual(rx[0][ARP].pdst, self.pg2.remote_ip4)
+        self.assertEqual(rx[0][ARP].pdst, self.pg3.remote_ip4)
         self.pg_enable_capture(self.pg_interfaces)
 
         #
         # At the end of this procedure there should be a connected route
         # in the FIB
         #
-        self.assertTrue(find_route(self, self.pg2.local_ip4, 24))
-        self.assertTrue(find_route(self, self.pg2.local_ip4, 32))
+        self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
+        self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
 
         # remove the left over ARP entry
-        self.vapi.ip_neighbor_add_del(self.pg2.sw_if_index,
-                                      mactobinary(self.pg2.remote_mac),
-                                      self.pg2.remote_ip4,
+        self.vapi.ip_neighbor_add_del(self.pg3.sw_if_index,
+                                      mactobinary(self.pg3.remote_mac),
+                                      self.pg3.remote_ip4,
                                       is_add=0)
         #
         # remove the DHCP config
         #
-        self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0)
+        self.vapi.dhcp_client(self.pg3.sw_if_index, hostname, is_add=0)
 
         #
         # and now the route should be gone
         #
-        self.assertFalse(find_route(self, self.pg2.local_ip4, 32))
-        self.assertFalse(find_route(self, self.pg2.local_ip4, 24))
+        self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
+        self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
 
         #
         # Start the procedure again. this time have VPP send the client-ID
         #
-        self.pg2.admin_down()
+        self.pg3.admin_down()
         self.sleep(1)
-        self.pg2.admin_up()
-        self.vapi.dhcp_client(self.pg2.sw_if_index, hostname,
-                              client_id=self.pg2.local_mac)
+        self.pg3.admin_up()
+        self.vapi.dhcp_client(self.pg3.sw_if_index, hostname,
+                              client_id=self.pg3.local_mac)
 
-        rx = self.pg2.get_capture(1)
+        rx = self.pg3.get_capture(1)
 
-        self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname,
-                                       self.pg2.local_mac)
+        self.verify_orig_dhcp_discover(rx[0], self.pg3, hostname,
+                                       self.pg3.local_mac)
 
-        self.pg2.add_stream(p_offer)
+        self.pg3.add_stream(p_offer)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg2.get_capture(1)
-        self.verify_orig_dhcp_request(rx[0], self.pg2, hostname,
-                                      self.pg2.local_ip4)
+        rx = self.pg3.get_capture(1)
+        self.verify_orig_dhcp_request(rx[0], self.pg3, hostname,
+                                      self.pg3.local_ip4)
 
         #
         # unicast the ack to the offered address
         #
-        p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) /
-                 IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
+        p_ack = (Ether(dst=self.pg3.local_mac, src=self.pg3.remote_mac) /
+                 IP(src=self.pg3.remote_ip4, dst=self.pg3.local_ip4) /
                  UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) /
-                 BOOTP(op=1, yiaddr=self.pg2.local_ip4) /
+                 BOOTP(op=1, yiaddr=self.pg3.local_ip4) /
                  DHCP(options=[('message-type', 'ack'),
                                ('subnet_mask', "255.255.255.0"),
-                               ('router', self.pg2.remote_ip4),
-                               ('server_id', self.pg2.remote_ip4),
+                               ('router', self.pg3.remote_ip4),
+                               ('server_id', self.pg3.remote_ip4),
                                ('lease_time', 43200),
                                ('end')]))
 
-        self.pg2.add_stream(p_ack)
+        self.pg3.add_stream(p_ack)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
@@ -1193,16 +1321,16 @@ class TestDHCP(VppTestCase):
         # At the end of this procedure there should be a connected route
         # in the FIB
         #
-        self.assertTrue(find_route(self, self.pg2.local_ip4, 32))
-        self.assertTrue(find_route(self, self.pg2.local_ip4, 24))
+        self.assertTrue(find_route(self, self.pg3.local_ip4, 32))
+        self.assertTrue(find_route(self, self.pg3.local_ip4, 24))
 
         #
         # remove the DHCP config
         #
-        self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0)
+        self.vapi.dhcp_client(self.pg3.sw_if_index, hostname, is_add=0)
 
-        self.assertFalse(find_route(self, self.pg2.local_ip4, 32))
-        self.assertFalse(find_route(self, self.pg2.local_ip4, 24))
+        self.assertFalse(find_route(self, self.pg3.local_ip4, 32))
+        self.assertFalse(find_route(self, self.pg3.local_ip4, 24))
 
 
 if __name__ == '__main__':
index 66126c5..3dd3482 100644 (file)
@@ -2021,18 +2021,22 @@ class VppPapiProvider(object):
 
     def dhcp_proxy_set_vss(self,
                            table_id,
-                           fib_id,
-                           oui,
+                           vss_type=255,
+                           vpn_ascii_id="",
+                           oui=0,
+                           vpn_index=0,
                            is_add=1,
                            is_ip6=0):
         return self.api(
             self.papi.dhcp_proxy_set_vss,
             {
                 'tbl_id': table_id,
-                'fib_id': fib_id,
-                'is_ipv6': is_ip6,
-                'is_add': is_add,
+                'vss_type': vss_type,
+                'vpn_ascii_id': vpn_ascii_id,
                 'oui': oui,
+                'vpn_index': vpn_index,
+                'is_add': is_add,
+                'is_ipv6': is_ip6,
             })
 
     def dhcp_client(self,