Add Support of DHCP VSS Type 0 where VPN-ID is ASCII

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>
diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api
index 628b674..19650f5 100644
--- a/src/vnet/dhcp/dhcp.api
+++ b/src/vnet/dhcp/dhcp.api
@@ -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 @@
     @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 @@
   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 @@
   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;
diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c
index 339a788..cd52be8 100644
--- a/src/vnet/dhcp/dhcp4_proxy_node.c
+++ b/src/vnet/dhcp/dhcp4_proxy_node.c
@@ -229,19 +229,19 @@
                     }
                 }
               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 @@
               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;
+              if (vss)
+                {
+		  u32 id_len;			/* length of VPN ID */
 
-                  opt82_oui =  vss->oui;
-                  opt82_fib_id =  vss->fib_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 */
-                  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;
-                  }
-              }
+                  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 @@
               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 @@
            * 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 @@
                                                    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 @@
                       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 @@
                         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,
 };
 
diff --git a/src/vnet/dhcp/dhcp6_packet.h b/src/vnet/dhcp/dhcp6_packet.h
index ddcde7a..24a1814 100644
--- a/src/vnet/dhcp/dhcp6_packet.h
+++ b/src/vnet/dhcp/dhcp6_packet.h
@@ -164,7 +164,8 @@
 
 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 {
diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c
index ce7a8fc..3cac278 100644
--- a/src/vnet/dhcp/dhcp6_proxy_node.c
+++ b/src/vnet/dhcp/dhcp6_proxy_node.c
@@ -330,31 +330,40 @@
                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 @@
                        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 @@
   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,
 };
 
diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c
index d6984f2..ad96e02 100644
--- a/src/vnet/dhcp/dhcp_api.c
+++ b/src/vnet/dhcp/dhcp_api.c
@@ -55,14 +55,16 @@
 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 @@
 
   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)
   {
diff --git a/src/vnet/dhcp/dhcp_proxy.c b/src/vnet/dhcp/dhcp_proxy.c
index 1784906..dae6312 100644
--- a/src/vnet/dhcp/dhcp_proxy.c
+++ b/src/vnet/dhcp/dhcp_proxy.c
@@ -278,19 +278,60 @@
 {
     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 @@
   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);
diff --git a/src/vnet/dhcp/dhcp_proxy.h b/src/vnet/dhcp/dhcp_proxy.h
index ef2bc0a..9b15ac8 100644
--- a/src/vnet/dhcp/dhcp_proxy.h
+++ b/src/vnet/dhcp/dhcp_proxy.h
@@ -48,13 +48,24 @@
  */
 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 @@
 /**
  * @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