]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: add vrf-policy config using existing vnc code
authorLou Berger <lberger@labn.net>
Thu, 12 Jan 2017 13:30:17 +0000 (08:30 -0500)
committerLou Berger <lberger@labn.net>
Mon, 23 Jan 2017 01:54:57 +0000 (20:54 -0500)
      add add/clear vrf prefix
      + Modified for FRR master parser

Signed-off-by: Lou Berger <lberger@labn.net>
13 files changed:
bgpd/bgp_mplsvpn.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/bgp_rfapi_cfg.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_import.h
bgpd/rfapi/rfapi_private.h
bgpd/rfapi/rfapi_rib.c
bgpd/rfapi/rfapi_vty.c
lib/command.c
lib/command.h
lib/vty.c
vtysh/vtysh.c

index 336b736169950ab0aa397011374117ec1ae9f62d..234cf9baa299c28e089858d3f3a8fad004e295bb 100644 (file)
@@ -30,6 +30,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 #define RD_ADDRSTRLEN  28
 
+#ifdef MPLS_LABEL_MAX
+# undef MPLS_LABEL_MAX
+#endif
+
 typedef enum {
     MPLS_LABEL_IPV4_EXPLICIT_NULL = 0,  /* [RFC3032] */
     MPLS_LABEL_ROUTER_ALERT       = 1,  /* [RFC3032] */
@@ -45,7 +49,9 @@ typedef enum {
     MPLS_LABEL_UNASSIGNED11       = 11,
     MPLS_LABEL_GAL                = 13, /* [RFC5586] */
     MPLS_LABEL_OAM_ALERT          = 14, /* [RFC3429] */
-    MPLS_LABEL_EXTENSION          = 15  /* [RFC7274] */
+    MPLS_LABEL_EXTENSION          = 15,  /* [RFC7274] */
+    MPLS_LABEL_MAX                = 1048575,
+    MPLS_LABEL_ILLEGAL            = 0xFFFFFFFF /* for internal use only */
 } mpls_special_label_t;
 
 #define MPLS_LABEL_IS_SPECIAL(label)             \
index ab9a24e831cfb2e2c1979ab6e27b9f2b938d307d..a2b0be3cc6cebdc95f2e593b6526b24893a8e2f5 100644 (file)
@@ -561,8 +561,9 @@ DEFUN (vnc_defaults_responselifetime,
   return CMD_SUCCESS;
 }
 
-static struct rfapi_nve_group_cfg *
-rfapi_group_lookup_byname (struct bgp *bgp, const char *name)
+struct rfapi_nve_group_cfg *
+bgp_rfapi_cfg_match_byname (struct bgp *bgp, const char *name,
+                           rfapi_group_cfg_type_t type)  /* _MAX = any */
 {
   struct rfapi_nve_group_cfg *rfg;
   struct listnode *node, *nnode;
@@ -570,18 +571,29 @@ rfapi_group_lookup_byname (struct bgp *bgp, const char *name)
   for (ALL_LIST_ELEMENTS
        (bgp->rfapi_cfg->nve_groups_sequential, node, nnode, rfg))
     {
-      if (!strcmp (rfg->name, name))
+      if ((type == RFAPI_GROUP_CFG_MAX || type == rfg->type) &&
+          !strcmp (rfg->name, name))
         return rfg;
     }
   return NULL;
 }
 
 static struct rfapi_nve_group_cfg *
-rfapi_group_new ()
+rfapi_group_new (struct bgp *bgp,
+                 rfapi_group_cfg_type_t type,
+                 const char *name)
 {
   struct rfapi_nve_group_cfg *rfg;
 
   rfg = XCALLOC (MTYPE_RFAPI_GROUP_CFG, sizeof (struct rfapi_nve_group_cfg));
+  if (rfg) 
+    {
+      rfg->type = type;
+      rfg->name = strdup (name);
+      /* add to tail of list */
+      listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);
+    }
+  rfg->label = MPLS_LABEL_ILLEGAL;
   QOBJ_REG (rfg, rfapi_nve_group_cfg);
 
   return rfg;
@@ -1033,7 +1045,8 @@ DEFUN (vnc_redistribute_nvegroup,
    * OK if nve group doesn't exist yet; we'll set the pointer
    * when the group is defined later
    */
-  bgp->rfapi_cfg->rfg_redist = rfapi_group_lookup_byname (bgp, argv[3]->arg);
+  bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname (bgp, argv[3]->arg,
+                                                           RFAPI_GROUP_CFG_NVE);
   if (bgp->rfapi_cfg->rfg_redist_name)
     free (bgp->rfapi_cfg->rfg_redist_name);
   bgp->rfapi_cfg->rfg_redist_name = strdup (argv[3]->arg);
@@ -1622,7 +1635,7 @@ DEFUN (vnc_export_nvegroup,
       return CMD_WARNING;
     }
 
-  rfg_new = rfapi_group_lookup_byname (bgp, argv[5]->arg);
+  rfg_new = bgp_rfapi_cfg_match_byname (bgp, argv[5]->arg, RFAPI_GROUP_CFG_NVE);
 
   if (argv[2]->arg[0] == 'b')
     {
@@ -2417,20 +2430,17 @@ DEFUN (vnc_nve_group,
   struct rfapi_rfg_name *rfgn;
 
   /* Search for name */
-  rfg = rfapi_group_lookup_byname (bgp, argv[2]->arg);
+  rfg = bgp_rfapi_cfg_match_byname (bgp, argv[2]->arg, RFAPI_GROUP_CFG_NVE);
 
   if (!rfg)
     {
-      rfg = rfapi_group_new ();
+      rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_NVE, argv[2]->arg);
       if (!rfg)
         {
           /* Error out of memory */
           vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);
           return CMD_WARNING;
         }
-      rfg->name = strdup (argv[2]->arg);
-      /* add to tail of list */
-      listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);
 
       /* Copy defaults from struct rfapi_cfg */
       rfg->rd = bgp->rfapi_cfg->default_rd;
@@ -2629,7 +2639,8 @@ static int
 bgp_rfapi_delete_named_nve_group (
   struct vty *vty,      /* NULL = no output */
   struct bgp *bgp,
-  const char *rfg_name)        /* NULL = any */
+  const char *rfg_name, /* NULL = any */
+  rfapi_group_cfg_type_t type)  /* _MAX = any */
 {
   struct rfapi_nve_group_cfg *rfg = NULL;
   struct listnode *node, *nnode;
@@ -2638,7 +2649,7 @@ bgp_rfapi_delete_named_nve_group (
   /* Search for name */
   if (rfg_name)
     {
-      rfg = rfapi_group_lookup_byname (bgp, rfg_name);
+      rfg = bgp_rfapi_cfg_match_byname (bgp, rfg_name, type);
       if (!rfg)
         {
           if (vty)
@@ -2665,7 +2676,8 @@ bgp_rfapi_delete_named_nve_group (
   for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
                              node, rfgn))
     {
-      if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name))
+      if (rfg_name == NULL ||
+          (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))
         {
           rfgn->rfg = NULL;
           /* remove exported routes from this group */
@@ -2680,7 +2692,8 @@ bgp_rfapi_delete_named_nve_group (
   for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
     {
 
-      if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name))
+      if (rfg_name == NULL ||
+          (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))
         {
           rfgn->rfg = NULL;
           /* remove exported routes from this group */
@@ -2707,7 +2720,7 @@ DEFUN (vnc_no_nve_group,
 {
   VTY_DECLVAR_CONTEXT(bgp, bgp);
 
-  return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg);
+  return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE);
 }
 
 DEFUN (vnc_nve_group_prefix,
@@ -3238,238 +3251,198 @@ static struct cmd_node bgp_vnc_nve_group_node = {
 };
 
 /*-------------------------------------------------------------------------
- *                     vnc-l2-group
+ *                     VNC nve-group
+ * Note there are two types of NVEs, one for VPNs one for RFP NVEs
  *-----------------------------------------------------------------------*/
 
-
-DEFUN (vnc_l2_group,
-       vnc_l2_group_cmd,
-       "vnc l2-group NAME",
-       VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n")
+DEFUN (vnc_vrf_policy,
+       vnc_vrf_policy_cmd,
+       "vrf-policy NAME",
+       "Configure a VRF policy group\n"
+       "VRF name\n")
 {
+  struct rfapi_nve_group_cfg *rfg;
   VTY_DECLVAR_CONTEXT(bgp, bgp);
-  struct rfapi_l2_group_cfg *rfg;
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
 
   /* Search for name */
-  rfg = rfapi_l2_group_lookup_byname (bgp, argv[2]->arg);
+  rfg = bgp_rfapi_cfg_match_byname (bgp, argv[1]->arg, RFAPI_GROUP_CFG_VRF);
 
   if (!rfg)
     {
-      rfg = rfapi_l2_group_new ();
+      rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_VRF, argv[1]->arg);
       if (!rfg)
         {
           /* Error out of memory */
-          vty_out (vty, "Can't allocate memory for L2 group%s", VTY_NEWLINE);
+          vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);
           return CMD_WARNING;
         }
-      rfg->name = strdup (argv[2]->arg);
-      /* add to tail of list */
-      listnode_add (bgp->rfapi_cfg->l2_groups, rfg);
     }
-
   /*
    * XXX subsequent calls will need to make sure this item is still
    * in the linked list and has the same name
    */
-  VTY_PUSH_CONTEXT_SUB (BGP_VNC_L2_GROUP_NODE, rfg);
-  return CMD_SUCCESS;
-}
-
-static void
-bgp_rfapi_delete_l2_group (
-  struct vty                   *vty,     /* NULL = no output */
-  struct bgp                   *bgp,
-  struct rfapi_l2_group_cfg    *rfg)
-{
-  /* delete it */
-  free (rfg->name);
-  if (rfg->rt_import_list)
-    ecommunity_free (&rfg->rt_import_list);
-  if (rfg->rt_export_list)
-    ecommunity_free (&rfg->rt_export_list);
-  if (rfg->labels)
-    list_delete (rfg->labels);
-  if (rfg->rfp_cfg)
-    XFREE (MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg);
-  listnode_delete (bgp->rfapi_cfg->l2_groups, rfg);
-
-  rfapi_l2_group_del (rfg);
-}
-
-static int
-bgp_rfapi_delete_named_l2_group (
-  struct vty *vty,       /* NULL = no output */
-  struct bgp *bgp,
-  const char *rfg_name) /* NULL = any */
-{
-  struct rfapi_l2_group_cfg *rfg = NULL;
-  struct listnode *node, *nnode;
-
-  /* Search for name */
-  if (rfg_name)
-    {
-      rfg = rfapi_l2_group_lookup_byname (bgp, rfg_name);
-      if (!rfg)
-        {
-          if (vty)
-            vty_out (vty, "No L2 group named \"%s\"%s", rfg_name,
-                     VTY_NEWLINE);
-          return CMD_WARNING;
-        }
-    }
+  VTY_PUSH_CONTEXT_SUB (BGP_VRF_POLICY_NODE, rfg);
 
-  if (rfg)
-    bgp_rfapi_delete_l2_group (vty, bgp, rfg);
-  else                          /* must be delete all */
-    for (ALL_LIST_ELEMENTS (bgp->rfapi_cfg->l2_groups, node, nnode, rfg))
-      bgp_rfapi_delete_l2_group (vty, bgp, rfg);
   return CMD_SUCCESS;
 }
 
-DEFUN (vnc_no_l2_group,
-       vnc_no_l2_group_cmd,
-       "no vnc l2-group NAME",
+DEFUN (vnc_no_vrf_policy,
+       vnc_no_vrf_policy_cmd,
+       "no vrf-policy NAME",
        NO_STR
-       VNC_CONFIG_STR
-       "Configure a L2 group\n"
-       "Group name\n")
+       "Remove a VRF policy group\n"
+       "VRF name\n")
 {
   VTY_DECLVAR_CONTEXT(bgp, bgp);
 
-  return bgp_rfapi_delete_named_l2_group (vty, bgp, argv[3]->arg);
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[2]->arg, RFAPI_GROUP_CFG_VRF);
 }
 
-
-DEFUN (vnc_l2_group_lni,
-       vnc_l2_group_lni_cmd,
-       "logical-network-id (0-4294967295)",
-       "Specify Logical Network ID associated with group\n"
-       "value\n")
+DEFUN (vnc_vrf_policy_label,
+       vnc_vrf_policy_label_cmd,
+       "label (0-1048575)",
+       "Default label value for VRF\n"
+       "Label Value <0-1048575>\n")
 {
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+
+  uint32_t label;
   VTY_DECLVAR_CONTEXT(bgp, bgp);
-  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
 
   /* make sure it's still in list */
-  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
     {
       /* Not in list anymore */
-      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
-  VTY_GET_INTEGER ("logical-network-id", rfg->logical_net_id, argv[1]->arg);
+  VTY_GET_INTEGER_RANGE ("Label value", label, argv[1]->arg, 0, MPLS_LABEL_MAX);
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_prechange (bgp);
+    }
 
+  rfg->label = label;
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_postchange (bgp);
+    }
   return CMD_SUCCESS;
 }
 
-DEFUN (vnc_l2_group_labels,
-       vnc_l2_group_labels_cmd,
-       "labels LABELLIST...",
-       "Specify label values associated with group\n"
-       "Space separated list of label values <0-1048575>\n")
+DEFUN (vnc_vrf_policy_no_label,
+       vnc_vrf_policy_no_label_cmd,
+       "no label",
+       "Remove VRF default label\n")
 {
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
   VTY_DECLVAR_CONTEXT(bgp, bgp);
-  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
-  struct list *ll;
 
   /* make sure it's still in list */
-  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
     {
       /* Not in list anymore */
-      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      vty_out (vty, "Current VRF group no longer exists%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
-  ll = rfg->labels;
-  if (ll == NULL)
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
     {
-      ll = list_new ();
-      rfg->labels = ll;
+      vnc_redistribute_prechange (bgp);
     }
 
-  argc -= 1;
-  argv += 1;
-  for (; argc; --argc, ++argv)
+  rfg->label = MPLS_LABEL_ILLEGAL;
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
     {
-      uint32_t label;
-      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575);
-      if (!listnode_lookup (ll, (void *) (uintptr_t) label))
-        listnode_add (ll, (void *) (uintptr_t) label);
+      vnc_redistribute_postchange (bgp);
     }
-
   return CMD_SUCCESS;
 }
 
-DEFUN (vnc_l2_group_no_labels,
-       vnc_l2_group_no_labels_cmd,
-       "no labels LABELLIST...",
-       NO_STR
-       "Remove label values associated with L2 group\n"
-       "Specify label values associated with L2 group\n"
-       "Space separated list of label values <0-1048575>\n")
+DEFUN (vnc_vrf_policy_nexthop,
+       vnc_vrf_policy_nexthop_cmd,
+       "nexthop <A.B.C.D|X:X::X:X|self>",
+       "Specify next hop to use for VRF advertised prefixes\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "Use configured router-id (default)")
 {
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+  struct prefix p;
+
   VTY_DECLVAR_CONTEXT(bgp, bgp);
-  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
-  struct list *ll;
 
   /* make sure it's still in list */
-  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
     {
       /* Not in list anymore */
-      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      vty_out (vty, "Current VRF no longer exists%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
-  ll = rfg->labels;
-  if (ll == NULL)
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
     {
-      vty_out (vty, "Label no longer associated with group%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      vnc_redistribute_prechange (bgp);
     }
 
-  argc -= 2;
-  argv += 2;
-  for (; argc; --argc, ++argv)
+  if (!str2prefix (argv[1]->arg, &p) && p.family)
     {
-      uint32_t label;
-      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575);
-      listnode_delete (ll, (void *) (uintptr_t) label);
+      //vty_out (vty, "Nexthop set to self%s", VTY_NEWLINE);
+      SET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF);
+      memset(&rfg->vn_prefix, 0, sizeof(struct prefix));
+    }
+  else
+    {
+      UNSET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF);
+      rfg->vn_prefix = p;
+    }
+
+  /* TBD handle router-id/ nexthop changes when have advertised prefixes */
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_postchange (bgp);
     }
 
   return CMD_SUCCESS;
 }
 
-DEFUN (vnc_l2_group_rt,
-       vnc_l2_group_rt_cmd,
-       "rt <both|export|import> ASN:nn_or_IP-address:nn",
+/* The RT code should be refactored/simplified with above... */
+DEFUN (vnc_vrf_policy_rt_import,
+       vnc_vrf_policy_rt_import_cmd,
+       "rt import RTLIST...",
        "Specify route targets\n"
-       "Export+import filters\n"
-       "Export filters\n"
-       "Import filters\n"
-       "A route target\n")
+       "Import filter\n"
+       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
 {
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
   VTY_DECLVAR_CONTEXT(bgp, bgp);
-  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
-  int rc = CMD_SUCCESS;
-  int do_import = 0;
-  int do_export = 0;
-
-  switch (argv[1]->arg[0])
-    {
-    case 'b':
-      do_export = 1;            /* fall through */
-    case 'i':
-      do_import = 1;
-      break;
-    case 'e':
-      do_export = 1;
-      break;
-    default:
-      vty_out (vty, "Unknown option, %s%s", argv[1]->arg, VTY_NEWLINE);
-      return CMD_ERR_NO_MATCH;
-    }
-  if (argc < 3)
-    return CMD_ERR_INCOMPLETE;
+  int rc;
+  struct listnode *node;
+  struct rfapi_rfg_name *rfgn;
+  int is_export_bgp = 0;
+  int is_export_zebra = 0;
 
   if (!bgp)
     {
@@ -3478,44 +3451,596 @@ DEFUN (vnc_l2_group_rt,
     }
 
   /* make sure it's still in list */
-  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
     {
       /* Not in list anymore */
-      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
-  if (do_import)
-    rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_import_list);
-  if (rc == CMD_SUCCESS && do_export)
-    rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_export_list);
-  return rc;
-}
-
-
-static struct cmd_node bgp_vnc_l2_group_node = {
-  BGP_VNC_L2_GROUP_NODE,
-  "%s(config-router-vnc-l2-group)# ",
-  1
-};
+  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+  if (rc != CMD_SUCCESS)
+    return rc;
 
-struct rfapi_l2_group_cfg *
-bgp_rfapi_get_group_by_lni_label (
-  struct bgp   *bgp,
-  uint32_t     logical_net_id,
-  uint32_t     label)
-{
-  struct rfapi_l2_group_cfg *rfg;
-  struct listnode *node;
+  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
+                             node, rfgn))
+    {
 
-  if (bgp->rfapi_cfg->l2_groups == NULL)        /* not the best place for this */
-    return NULL;
+      if (rfgn->rfg == rfg)
+        {
+          is_export_bgp = 1;
+          break;
+        }
+    }
 
-  label = label & 0xfffff;      /* label is 20 bits! */
+  if (is_export_bgp)
+    vnc_direct_bgp_del_group (bgp, rfg);
 
-  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->l2_groups, node, rfg))
+  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
     {
-      if (rfg->logical_net_id == logical_net_id)
+
+      if (rfgn->rfg == rfg)
+        {
+          is_export_zebra = 1;
+          break;
+        }
+    }
+
+  if (is_export_zebra)
+    vnc_zebra_del_group (bgp, rfg);
+
+  /*
+   * stop referencing old import table, now reference new one
+   */
+  if (rfg->rfapi_import_table)
+    rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
+  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+
+  if (is_export_bgp)
+    vnc_direct_bgp_add_group (bgp, rfg);
+
+  if (is_export_zebra)
+    vnc_zebra_add_group (bgp, rfg);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_rt_export,
+       vnc_vrf_policy_rt_export_cmd,
+       "rt export RTLIST...",
+       "Specify route targets\n"
+       "Export filter\n"
+       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+  int rc;
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_prechange (bgp);
+    }
+
+  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_postchange (bgp);
+    }
+
+  return rc;
+}
+
+DEFUN (vnc_vrf_policy_rt_both,
+       vnc_vrf_policy_rt_both_cmd,
+       "rt both RTLIST...",
+       "Specify route targets\n"
+       "Export+import filters\n"
+       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+  int rc;
+  int is_export_bgp = 0;
+  int is_export_zebra = 0;
+  struct listnode *node;
+  struct rfapi_rfg_name *rfgn;
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+  if (rc != CMD_SUCCESS)
+    return rc;
+
+  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
+                             node, rfgn))
+    {
+
+      if (rfgn->rfg == rfg)
+        {
+          is_export_bgp = 1;
+          break;
+        }
+    }
+
+  if (is_export_bgp)
+    vnc_direct_bgp_del_group (bgp, rfg);
+
+  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
+    {
+
+      if (rfgn->rfg == rfg)
+        {
+          is_export_zebra = 1;
+          break;
+        }
+    }
+
+  if (is_export_zebra)
+    {
+      vnc_zlog_debug_verbose ("%s: is_export_zebra", __func__);
+      vnc_zebra_del_group (bgp, rfg);
+    }
+
+  /*
+   * stop referencing old import table, now reference new one
+   */
+  if (rfg->rfapi_import_table)
+    rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
+  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+
+  if (is_export_bgp)
+    vnc_direct_bgp_add_group (bgp, rfg);
+
+  if (is_export_zebra)
+    vnc_zebra_add_group (bgp, rfg);
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_prechange (bgp);
+    }
+
+  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_postchange (bgp);
+    }
+
+  return rc;
+
+}
+
+DEFUN (vnc_vrf_policy_rd,
+       vnc_vrf_policy_rd_cmd,
+       "rd ASN:nn_or_IP-address:nn",
+       "Specify default VRF route distinguisher\n"
+       "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:nh:<number> )\n")
+{
+  int ret;
+  struct prefix_rd prd;
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (!strncmp (argv[1]->arg, "auto:nh:", 8))
+    {
+      /*
+       * use AF_UNIX to designate automatically-assigned RD
+       * auto:vn:nn where nn is a 2-octet quantity
+       */
+      char *end = NULL;
+      uint32_t value32 = strtoul (argv[1]->arg + 8, &end, 10);
+      uint16_t value = value32 & 0xffff;
+
+      if (!*(argv[1]->arg + 5) || *end)
+        {
+          vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      if (value32 > 0xffff)
+        {
+          vty_out (vty, "%% Malformed rd (must be less than %u%s",
+                   0x0ffff, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+
+      memset (&prd, 0, sizeof (prd));
+      prd.family = AF_UNIX;
+      prd.prefixlen = 64;
+      prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff;
+      prd.val[1] = RD_TYPE_IP & 0x0ff;
+      prd.val[6] = (value >> 8) & 0x0ff;
+      prd.val[7] = value & 0x0ff;
+
+    }
+  else
+    {
+
+      ret = str2prefix_rd (argv[1]->arg, &prd);
+      if (!ret)
+        {
+          vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_prechange (bgp);
+    }
+
+  rfg->rd = prd;
+
+  if (bgp->rfapi_cfg->rfg_redist == rfg)
+    {
+      vnc_redistribute_postchange (bgp);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (exit_vrf_policy,
+       exit_vrf_policy_cmd,
+       "exit-vrf-policy",
+       "Exit VRF policy configuration mode\n")
+{
+  if (vty->node == BGP_VRF_POLICY_NODE)
+    {
+      vty->node = BGP_NODE;
+    }
+  return CMD_SUCCESS;
+}
+
+static struct cmd_node bgp_vrf_policy_node = {
+  BGP_VRF_POLICY_NODE,
+  "%s(config-router-vrf-policy)# ",
+  1
+};
+
+/*-------------------------------------------------------------------------
+ *                     vnc-l2-group
+ *-----------------------------------------------------------------------*/
+
+
+DEFUN (vnc_l2_group,
+       vnc_l2_group_cmd,
+       "vnc l2-group NAME",
+       VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n")
+{
+  struct rfapi_l2_group_cfg *rfg;
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Search for name */
+  rfg = rfapi_l2_group_lookup_byname (bgp, argv[1]->arg);
+
+  if (!rfg)
+    {
+      rfg = rfapi_l2_group_new ();
+      if (!rfg)
+        {
+          /* Error out of memory */
+          vty_out (vty, "Can't allocate memory for L2 group%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      rfg->name = strdup (argv[1]->arg);
+      /* add to tail of list */
+      listnode_add (bgp->rfapi_cfg->l2_groups, rfg);
+    }
+
+  /*
+   * XXX subsequent calls will need to make sure this item is still
+   * in the linked list and has the same name
+   */
+  VTY_PUSH_CONTEXT_SUB (BGP_VNC_L2_GROUP_NODE, rfg);
+  return CMD_SUCCESS;
+}
+
+static void
+bgp_rfapi_delete_l2_group (
+  struct vty                   *vty,     /* NULL = no output */
+  struct bgp                   *bgp,
+  struct rfapi_l2_group_cfg    *rfg)
+{
+  /* delete it */
+  free (rfg->name);
+  if (rfg->rt_import_list)
+    ecommunity_free (&rfg->rt_import_list);
+  if (rfg->rt_export_list)
+    ecommunity_free (&rfg->rt_export_list);
+  if (rfg->labels)
+    list_delete (rfg->labels);
+  if (rfg->rfp_cfg)
+    XFREE (MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg);
+  listnode_delete (bgp->rfapi_cfg->l2_groups, rfg);
+
+  rfapi_l2_group_del (rfg);
+}
+
+static int
+bgp_rfapi_delete_named_l2_group (
+  struct vty *vty,       /* NULL = no output */
+  struct bgp *bgp,
+  const char *rfg_name) /* NULL = any */
+{
+  struct rfapi_l2_group_cfg *rfg = NULL;
+  struct listnode *node, *nnode;
+
+  /* Search for name */
+  if (rfg_name)
+    {
+      rfg = rfapi_l2_group_lookup_byname (bgp, rfg_name);
+      if (!rfg)
+        {
+          if (vty)
+            vty_out (vty, "No L2 group named \"%s\"%s", rfg_name,
+                     VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+
+  if (rfg)
+    bgp_rfapi_delete_l2_group (vty, bgp, rfg);
+  else                          /* must be delete all */
+    for (ALL_LIST_ELEMENTS (bgp->rfapi_cfg->l2_groups, node, nnode, rfg))
+      bgp_rfapi_delete_l2_group (vty, bgp, rfg);
+  return CMD_SUCCESS;
+}
+
+DEFUN (vnc_no_l2_group,
+       vnc_no_l2_group_cmd,
+       "no vnc l2-group NAME",
+       NO_STR
+       VNC_CONFIG_STR
+       "Configure a L2 group\n"
+       "Group name\n")
+{
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_rfapi_delete_named_l2_group (vty, bgp, argv[3]->arg);
+}
+
+
+DEFUN (vnc_l2_group_lni,
+       vnc_l2_group_lni_cmd,
+       "logical-network-id <0-4294967295>",
+       "Specify Logical Network ID associated with group\n"
+       "value\n")
+{
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  VTY_GET_INTEGER ("logical-network-id", rfg->logical_net_id, argv[1]->arg);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (vnc_l2_group_labels,
+       vnc_l2_group_labels_cmd,
+       "labels .LABELLIST",
+       "Specify label values associated with group\n"
+       "Space separated list of label values <0-1048575>\n")
+{
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+  struct list *ll;
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ll = rfg->labels;
+  if (ll == NULL)
+    {
+      ll = list_new ();
+      rfg->labels = ll;
+    }
+  argc--;
+  argv++;
+  for (; argc; --argc, ++argv)
+    {
+      uint32_t label;
+      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);
+      if (!listnode_lookup (ll, (void *) (uintptr_t) label))
+        listnode_add (ll, (void *) (uintptr_t) label);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (vnc_l2_group_no_labels,
+       vnc_l2_group_no_labels_cmd,
+       "no labels .LABELLIST",
+       NO_STR
+       "Remove label values associated with L2 group\n"
+       "Specify label values associated with L2 group\n"
+       "Space separated list of label values <0-1048575>\n")
+{
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+  struct list *ll;
+
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ll = rfg->labels;
+  if (ll == NULL)
+    {
+      vty_out (vty, "Label no longer associated with group%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  argc-=2;
+  argv+=2;
+  for (; argc; --argc, ++argv)
+    {
+      uint32_t label;
+      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);
+      listnode_delete (ll, (void *) (uintptr_t) label);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (vnc_l2_group_rt,
+       vnc_l2_group_rt_cmd,
+       "rt <both|export|import> ASN:nn_or_IP-address:nn",
+       "Specify route targets\n"
+       "Export+import filters\n"
+       "Export filters\n"
+       "Import filters\n"
+       "A route target\n")
+{
+  VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+  VTY_DECLVAR_CONTEXT(bgp, bgp);
+  int rc = CMD_SUCCESS;
+  int do_import = 0;
+  int do_export = 0;
+
+  switch (argv[1]->arg[0])
+    {
+    case 'b':
+      do_export = 1;            /* fall through */
+    case 'i':
+      do_import = 1;
+      break;
+    case 'e':
+      do_export = 1;
+      break;
+    default:
+      vty_out (vty, "Unknown option, %s%s", argv[1]->arg, VTY_NEWLINE);
+      return CMD_ERR_NO_MATCH;
+
+    }
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* make sure it's still in list */
+  if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
+    {
+      /* Not in list anymore */
+      vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (do_import)
+    rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+  if (rc == CMD_SUCCESS && do_export)
+    rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+  return rc;
+}
+
+
+static struct cmd_node bgp_vnc_l2_group_node = {
+  BGP_VNC_L2_GROUP_NODE,
+  "%s(config-router-vnc-l2-group)# ",
+  1
+};
+
+struct rfapi_l2_group_cfg *
+bgp_rfapi_get_group_by_lni_label (
+  struct bgp   *bgp,
+  uint32_t     logical_net_id,
+  uint32_t     label)
+{
+  struct rfapi_l2_group_cfg *rfg;
+  struct listnode *node;
+
+  if (bgp->rfapi_cfg->l2_groups == NULL)        /* not the best place for this */
+    return NULL;
+
+  label = label & 0xfffff;      /* label is 20 bits! */
+
+  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->l2_groups, node, rfg))
+    {
+      if (rfg->logical_net_id == logical_net_id)
         {
           struct listnode *lnode;
           void *data;
@@ -3571,7 +4096,9 @@ bgp_rfapi_cfg_init (void)
 
   install_node (&bgp_vnc_defaults_node, NULL);
   install_node (&bgp_vnc_nve_group_node, NULL);
+  install_node (&bgp_vrf_policy_node, NULL);
   install_node (&bgp_vnc_l2_group_node, NULL);
+  install_default (BGP_VRF_POLICY_NODE);
   install_default (BGP_VNC_DEFAULTS_NODE);
   install_default (BGP_VNC_NVE_GROUP_NODE);
   install_default (BGP_VNC_L2_GROUP_NODE);
@@ -3582,6 +4109,8 @@ bgp_rfapi_cfg_init (void)
   install_element (BGP_NODE, &vnc_defaults_cmd);
   install_element (BGP_NODE, &vnc_nve_group_cmd);
   install_element (BGP_NODE, &vnc_no_nve_group_cmd);
+  install_element (BGP_NODE, &vnc_vrf_policy_cmd);
+  install_element (BGP_NODE, &vnc_no_vrf_policy_cmd);
   install_element (BGP_NODE, &vnc_l2_group_cmd);
   install_element (BGP_NODE, &vnc_no_l2_group_cmd);
   install_element (BGP_NODE, &vnc_advertise_un_method_cmd);
@@ -3645,6 +4174,16 @@ bgp_rfapi_cfg_init (void)
                    &vnc_nve_group_export_no_routemap_cmd);
   install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_cmd);
 
+  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_label_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_no_label_cmd);
+  //Hide per Jan 17 discussion
+  //install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_nexthop_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_import_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_export_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_both_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rd_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
+
   install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_lni_cmd);
   install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_labels_cmd);
   install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_no_labels_cmd);
@@ -3713,7 +4252,7 @@ bgp_rfapi_cfg_destroy (struct bgp *bgp, struct rfapi_cfg *h)
   if (h == NULL)
     return;
 
-  bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL);
+  bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL, RFAPI_GROUP_CFG_MAX);
   bgp_rfapi_delete_named_l2_group (NULL, bgp, NULL);
   if (h->l2_groups != NULL)
     list_delete (h->l2_groups);
@@ -3741,6 +4280,166 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
   afi_t afi;
   int type;
 
+  vty_out (vty, "!%s", VTY_NEWLINE);
+  for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg))
+    if (rfg->type == RFAPI_GROUP_CFG_VRF)
+      {
+        ++write;
+        vty_out (vty, " vrf-policy %s%s", rfg->name, VTY_NEWLINE);
+        if (rfg->label <= MPLS_LABEL_MAX)
+          {
+            vty_out (vty, "  label %u%s", rfg->label, VTY_NEWLINE);
+
+          }
+        if (CHECK_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF))
+          {
+            vty_out (vty, "  nexthop self%s", VTY_NEWLINE);
+
+          }
+        else 
+          {
+            if (rfg->vn_prefix.family)
+              {
+                char buf[BUFSIZ];
+                buf[0] = buf[BUFSIZ - 1] = 0;
+                inet_ntop(rfg->vn_prefix.family, &rfg->vn_prefix.u.prefix, buf, sizeof(buf));
+                if (!buf[0] || buf[BUFSIZ - 1])
+                  {
+                    //vty_out (vty, "nexthop self%s", VTY_NEWLINE);
+                  }
+                else
+                  {
+                    vty_out (vty, "  nexthop %s%s", buf, VTY_NEWLINE);
+                  }
+              }
+          }
+
+        if (rfg->rd.prefixlen)
+          {
+            char buf[BUFSIZ];
+            buf[0] = buf[BUFSIZ - 1] = 0;
+
+            if (AF_UNIX == rfg->rd.family)
+              {
+
+                uint16_t value = 0;
+
+                value = ((rfg->rd.val[6] << 8) & 0x0ff00) |
+                  (rfg->rd.val[7] & 0x0ff);
+
+                vty_out (vty, "  rd auto:nh:%d%s", value, VTY_NEWLINE);
+
+              }
+            else
+              {
+
+                if (!prefix_rd2str (&rfg->rd, buf, BUFSIZ) ||
+                    !buf[0] || buf[BUFSIZ - 1])
+                  {
+
+                    vty_out (vty, "!Error: Can't convert rd%s", VTY_NEWLINE);
+                  }
+                else
+                  {
+                    vty_out (vty, "  rd %s%s", buf, VTY_NEWLINE);
+                  }
+              }
+          }
+
+        if (rfg->rt_import_list && rfg->rt_export_list &&
+            ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
+          {
+            char *b = ecommunity_ecom2str (rfg->rt_import_list,
+                                           ECOMMUNITY_FORMAT_ROUTE_MAP);
+            vty_out (vty, "  rt both %s%s", b, VTY_NEWLINE);
+            XFREE (MTYPE_ECOMMUNITY_STR, b);
+          }
+        else
+          {
+            if (rfg->rt_import_list)
+              {
+                char *b = ecommunity_ecom2str (rfg->rt_import_list,
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                vty_out (vty, "  rt import %s%s", b, VTY_NEWLINE);
+                XFREE (MTYPE_ECOMMUNITY_STR, b);
+              }
+            if (rfg->rt_export_list)
+              {
+                char *b = ecommunity_ecom2str (rfg->rt_export_list,
+                                               ECOMMUNITY_FORMAT_ROUTE_MAP);
+                vty_out (vty, "  rt export %s%s", b, VTY_NEWLINE);
+                XFREE (MTYPE_ECOMMUNITY_STR, b);
+              }
+          }
+
+        /*
+         * route filtering: prefix-lists and route-maps
+         */
+        for (afi = AFI_IP; afi < AFI_MAX; ++afi)
+          {
+
+            const char *afistr = (afi == AFI_IP) ? "ipv4" : "ipv6";
+
+            if (rfg->plist_export_bgp_name[afi])
+              {
+                vty_out (vty, "  export bgp %s prefix-list %s%s",
+                         afistr, rfg->plist_export_bgp_name[afi],
+                         VTY_NEWLINE);
+              }
+            if (rfg->plist_export_zebra_name[afi])
+              {
+                vty_out (vty, "  export zebra %s prefix-list %s%s",
+                         afistr, rfg->plist_export_zebra_name[afi],
+                         VTY_NEWLINE);
+              }
+            /*
+             * currently we only support redist plists for bgp-direct.
+             * If we later add plist support for redistributing other
+             * protocols, we'll need to loop over protocols here
+             */
+            if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi])
+              {
+                vty_out (vty, "  redistribute bgp-direct %s prefix-list %s%s",
+                         afistr,
+                         rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi],
+                         VTY_NEWLINE);
+              }
+            if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT][afi])
+              {
+                vty_out (vty,
+                         "  redistribute bgp-direct-to-nve-groups %s prefix-list %s%s",
+                         afistr,
+                         rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT]
+                         [afi], VTY_NEWLINE);
+              }
+          }
+
+        if (rfg->routemap_export_bgp_name)
+          {
+            vty_out (vty, "  export bgp route-map %s%s",
+                     rfg->routemap_export_bgp_name, VTY_NEWLINE);
+          }
+        if (rfg->routemap_export_zebra_name)
+          {
+            vty_out (vty, "  export zebra route-map %s%s",
+                     rfg->routemap_export_zebra_name, VTY_NEWLINE);
+          }
+        if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT])
+          {
+            vty_out (vty, "  redistribute bgp-direct route-map %s%s",
+                     rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT],
+                     VTY_NEWLINE);
+          }
+        if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT])
+          {
+            vty_out (vty,
+                     "  redistribute bgp-direct-to-nve-groups route-map %s%s",
+                     rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT],
+                     VTY_NEWLINE);
+          }
+        vty_out (vty, "  exit-vrf-policy%s", VTY_NEWLINE);
+        vty_out (vty, "!%s", VTY_NEWLINE);
+      }
   if (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP)
     {
       vty_out (vty, " vnc advertise-un-method encap-safi%s", VTY_NEWLINE);
@@ -3902,6 +4601,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
       }
 
     for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg))
+      if (rfg->type == RFAPI_GROUP_CFG_NVE)
       {
         ++write;
         vty_out (vty, " vnc nve-group %s%s", rfg->name, VTY_NEWLINE);
index 897b4be7644188ab2820bc780d8e313139b15916..8f93d69f6b0f713df6e2c8f10992b239bee07b8a 100644 (file)
@@ -41,12 +41,21 @@ struct rfapi_l2_group_cfg
 };
 DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg)
 
+typedef enum
+{
+  RFAPI_GROUP_CFG_NVE = 1,
+  RFAPI_GROUP_CFG_VRF,
+  RFAPI_GROUP_CFG_L2,
+  RFAPI_GROUP_CFG_MAX
+} rfapi_group_cfg_type_t;
+
 struct rfapi_nve_group_cfg
 {
   struct route_node *vn_node;   /* backref */
   struct route_node *un_node;   /* backref */
 
-  char *name;
+  rfapi_group_cfg_type_t type;  /* NVE|VPN */
+  char *name;                   /* unique by type! */
   struct prefix vn_prefix;
   struct prefix un_prefix;
 
@@ -54,8 +63,9 @@ struct rfapi_nve_group_cfg
   uint8_t l2rd;                 /* 0 = VN addr LSB */
   uint32_t response_lifetime;
   uint32_t flags;
-#define RFAPI_RFG_RESPONSE_LIFETIME    0x1
+#define RFAPI_RFG_RESPONSE_LIFETIME    0x01 /* bits */
 #define RFAPI_RFG_L2RD                 0x02
+#define RFAPI_RFG_VPN_NH_SELF          0x04
   struct ecommunity *rt_import_list;
   struct ecommunity *rt_export_list;
   struct rfapi_import_table *rfapi_import_table;
@@ -99,6 +109,9 @@ struct rfapi_nve_group_cfg
   char *routemap_redist_name[ZEBRA_ROUTE_MAX];
   struct route_map *routemap_redist[ZEBRA_ROUTE_MAX];
 
+  /* for VRF type groups */
+  uint32_t                label;
+  struct rfapi_descriptor *rfd;
   QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg)
@@ -288,6 +301,12 @@ bgp_rfapi_cfg_match_group (
   struct prefix                *vn,
   struct prefix                *un);
 
+struct rfapi_nve_group_cfg *
+bgp_rfapi_cfg_match_byname (
+  struct bgp *bgp,
+  const char *name,
+  rfapi_group_cfg_type_t type);  /* _MAX = any */
+
 extern void
 vnc_prefix_list_update (struct bgp *bgp);
 
index 6353f7dacf62a15588d72e83cb27bc634a4ddc88..c195d09ce7f462b8fcd1e68922566b5b6e33675d 100644 (file)
@@ -335,6 +335,9 @@ is_valid_rfd (struct rfapi_descriptor *rfd)
   if (!rfd || rfd->bgp == NULL)
     return 0;
 
+  if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
+    return 1;
+
   if (rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh))
     return 0;
 
@@ -357,6 +360,9 @@ rfapi_check (void *handle)
   if (!rfd || rfd->bgp == NULL)
     return EINVAL;
 
+  if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
+    return 0;
+
   if ((rc = rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh)))
     return rc;
 
@@ -1347,7 +1353,6 @@ rfapi_rfp_set_cb_methods (void *rfp_start_val,
 /***********************************************************************
  *                     NVE Sessions
  ***********************************************************************/
-
 /*
  * Caller must supply an already-allocated rfd with the "caller"
  * fields already set (vn_addr, un_addr, callback, cookie)
@@ -1474,6 +1479,57 @@ rfapi_open_inner (
   return 0;
 }
 
+/* moved from rfapi_register */
+int
+rfapi_init_and_open(
+  struct bgp                   *bgp,
+  struct rfapi_descriptor      *rfd,
+  struct rfapi_nve_group_cfg   *rfg)
+{
+  struct rfapi *h = bgp->rfapi;
+  char buf_vn[BUFSIZ];
+  char buf_un[BUFSIZ];
+  afi_t afi_vn, afi_un;
+  struct prefix pfx_un;
+  struct route_node             *rn;
+
+
+  rfapi_time (&rfd->open_time);
+
+  if (rfg->type == RFAPI_GROUP_CFG_VRF)
+    SET_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF);
+
+  rfapiRfapiIpAddr2Str (&rfd->vn_addr, buf_vn, BUFSIZ);
+  rfapiRfapiIpAddr2Str (&rfd->un_addr, buf_un, BUFSIZ);
+
+  vnc_zlog_debug_verbose ("%s: new RFD with VN=%s UN=%s cookie=%p",
+                          __func__, buf_vn, buf_un, rfd->cookie);
+
+  if (rfg->type != RFAPI_GROUP_CFG_VRF) /* unclear if needed for VRF */
+    {
+      listnode_add (&h->descriptors, rfd);
+      if (h->descriptors.count > h->stat.max_descriptors)
+        {
+          h->stat.max_descriptors = h->descriptors.count;
+        }
+
+      /*
+       * attach to UN radix tree
+       */
+      afi_vn = family2afi (rfd->vn_addr.addr_family);
+      afi_un = family2afi (rfd->un_addr.addr_family);
+      assert (afi_vn && afi_un);
+      assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
+
+      rn = route_node_get (&(h->un[afi_un]), &pfx_un);
+      assert (rn);
+      rfd->next = rn->info;
+      rn->info = rfd;
+      rfd->un_node = rn;
+    }  
+  return rfapi_open_inner (rfd, bgp, h, rfg);
+}
+
 struct rfapi_vn_option *
 rfapiVnOptionsDup (struct rfapi_vn_option *orig)
 {
@@ -1991,14 +2047,10 @@ rfapi_open (
   struct prefix pfx_vn;
   struct prefix pfx_un;
 
-  struct route_node *rn;
   int rc;
   rfapi_handle hh = NULL;
   int reusing_provisional = 0;
 
-  afi_t afi_vn;
-  afi_t afi_un;
-
   {
     char buf[2][INET_ADDRSTRLEN];
     vnc_zlog_debug_verbose ("%s: VN=%s UN=%s", __func__,
@@ -2129,40 +2181,7 @@ rfapi_open (
 
   if (!reusing_provisional)
     {
-      rfapi_time (&rfd->open_time);
-
-      {
-        char buf_vn[BUFSIZ];
-        char buf_un[BUFSIZ];
-
-        rfapiRfapiIpAddr2Str (vn, buf_vn, BUFSIZ);
-        rfapiRfapiIpAddr2Str (un, buf_un, BUFSIZ);
-
-        vnc_zlog_debug_verbose ("%s: new HD with VN=%s UN=%s cookie=%p",
-                    __func__, buf_vn, buf_un, userdata);
-      }
-
-      listnode_add (&h->descriptors, rfd);
-      if (h->descriptors.count > h->stat.max_descriptors)
-        {
-          h->stat.max_descriptors = h->descriptors.count;
-        }
-
-      /*
-       * attach to UN radix tree
-       */
-      afi_vn = family2afi (rfd->vn_addr.addr_family);
-      afi_un = family2afi (rfd->un_addr.addr_family);
-      assert (afi_vn && afi_un);
-      assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
-
-      rn = route_node_get (&(h->un[afi_un]), &pfx_un);
-      assert (rn);
-      rfd->next = rn->info;
-      rn->info = rfd;
-      rfd->un_node = rn;
-
-      rc = rfapi_open_inner (rfd, bgp, h, rfg);
+      rc = rfapi_init_and_open(bgp, rfd, rfg);
       /*
        * This can fail only if the VN address is IPv6 and the group
        * specified auto-assignment of RDs, which only works for v4,
index 26325b5816ff2604fc50fb3e4ed0e686dffe38ee..5ba98e55d078a34928f12beb3db5a456d0080188 100644 (file)
@@ -4943,6 +4943,7 @@ rfapiDeleteRemotePrefixesIt (
  *     un                      if set, tunnel must match this prefix
  *     vn                      if set, nexthop prefix must match this prefix
  *     p                       if set, prefix must match this prefix
+ *      it                      if set, only look in this import table
  *
  * output
  *     pARcount                number of active routes deleted
@@ -4958,6 +4959,7 @@ rfapiDeleteRemotePrefixes (
     struct prefix      *un,
     struct prefix      *vn,
     struct prefix      *p,
+    struct rfapi_import_table *arg_it,
     int                        delete_active,
     int                        delete_holddown,
     uint32_t           *pARcount,
@@ -4995,7 +4997,11 @@ rfapiDeleteRemotePrefixes (
    * for the afi/safi combination
    */
 
-  for (it = h->imports; it; it = it->next)
+  if (arg_it)
+    it = arg_it;
+  else
+    it = h->imports;
+  for (; it; )
     {
 
       vnc_zlog_debug_verbose
@@ -5016,6 +5022,11 @@ rfapiDeleteRemotePrefixes (
        &deleted_holddown_nve_count,
        uniq_active_nves,
        uniq_holddown_nves);
+
+      if (arg_it)
+        it = NULL;
+      else
+        it = it->next;
     }
 
   /*
index 3cf55462a1f071d6f204b532cff8992673e363fb..51afa0002f5a8f905c696c29a124a35515960cb2 100644 (file)
@@ -223,6 +223,7 @@ extern int rfapiEcommunityGetEthernetTag (
  *     un                      if set, tunnel must match this prefix
  *     vn                      if set, nexthop prefix must match this prefix
  *     p                       if set, prefix must match this prefix
+ *      it                      if set, only look in this import table
  *
  * output
  *     pARcount                number of active routes deleted
@@ -238,6 +239,7 @@ rfapiDeleteRemotePrefixes (
   struct prefix        *un,
   struct prefix        *vn,
   struct prefix        *p,
+  struct rfapi_import_table *it,
   int          delete_active,
   int          delete_holddown,
   uint32_t     *pARcount,     /* active routes */
index 00f90e35fc827197dc07901516a68603e447bf21..ed83ef1e1f7629e4a1e40eac02f0b36503168251 100644 (file)
@@ -135,6 +135,7 @@ struct rfapi_descriptor
 #define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER     0x00000004
 #define RFAPI_HD_FLAG_PROVISIONAL                      0x00000008
 #define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY         0x00000010
+#define RFAPI_HD_FLAG_IS_VRF                           0x00000012
 };
 
 #define RFAPI_QUEUED_FLAG(afi) (                                       \
@@ -433,4 +434,17 @@ DECLARE_MTYPE(RFAPI_L2ADDR_OPT)
 DECLARE_MTYPE(RFAPI_AP)
 DECLARE_MTYPE(RFAPI_MONITOR_ETH)
 
+
+/*
+ * Caller must supply an already-allocated rfd with the "caller"
+ * fields already set (vn_addr, un_addr, callback, cookie)
+ * The advertised_prefixes[] array elements should be NULL to
+ * have this function set them to newly-allocated radix trees.
+ */
+extern int
+rfapi_init_and_open(
+  struct bgp                   *bgp,
+  struct rfapi_descriptor      *rfd,
+  struct rfapi_nve_group_cfg   *rfg);
+
 #endif /* _QUAGGA_BGP_RFAPI_PRIVATE_H */
index 3a4a1592155a89c6360689609644fa4a7c998d7c..8e5d47415f00ceb4709de4bc66fd5b2dcde0f7b4 100644 (file)
@@ -514,9 +514,13 @@ rfapi_info_cmp (struct rfapi_info *a, struct rfapi_info *b)
 void
 rfapiRibClear (struct rfapi_descriptor *rfd)
 {
-  struct bgp *bgp = bgp_get_default ();
+  struct bgp *bgp;
   afi_t afi;
 
+  if (rfd->bgp)
+    bgp = rfd->bgp;
+  else
+    bgp = bgp_get_default ();
 #if DEBUG_L2_EXTRA
   vnc_zlog_debug_verbose ("%s: rfd=%p", __func__, rfd);
 #endif
index ed3155307d69b85527c2e0135806f6ec46794b22..f8142ed299c0e199d805a93163f804cce79957f9 100644 (file)
@@ -3004,9 +3004,12 @@ struct rfapi_local_reg_delete_arg
   /*
    * match parameters
    */
+  struct bgp           *bgp;
   struct rfapi_ip_addr un_address;     /* AF==0: wildcard */
   struct rfapi_ip_addr vn_address;     /* AF==0: wildcard */
   struct prefix                prefix;         /* AF==0: wildcard */
+  struct prefix_rd     rd;             /* plen!=64: wildcard */
+  struct rfapi_nve_group_cfg *rfg;      /* NULL: wildcard */
 
   struct rfapi_l2address_option_match l2o;
 
@@ -3106,22 +3109,26 @@ nve_addr_cmp (void *k1, void *k2)
 
 static int
 parse_deleter_args (
-  struct vty                           *vty,
-  struct cmd_token                     *carg_prefix,
-  struct cmd_token                     *carg_vn,
-  struct cmd_token                     *carg_un,
-  struct cmd_token                     *carg_l2addr,
-  struct cmd_token                     *carg_vni,
-  struct rfapi_local_reg_delete_arg    *rcdarg)
+  struct vty                       *vty,
+  struct bgp                        *bgp,
+  const char                        *arg_prefix,
+  const char                        *arg_vn,
+  const char                        *arg_un,
+  const char                        *arg_l2addr,
+  const char                        *arg_vni,
+  const char                        *arg_rd,
+  struct rfapi_nve_group_cfg        *arg_rfg,
+  struct rfapi_local_reg_delete_arg *rcdarg)
 {
-  const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
-  const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
-  const char *arg_un = carg_un ? carg_un->arg : NULL;
-  const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
-  const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
   int rc = CMD_WARNING;
 
-    memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
+  memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
+
+  rcdarg->vty = vty;
+  if (bgp == NULL)
+    bgp = bgp_get_default();
+  rcdarg->bgp = bgp;
+  rcdarg->rfg = arg_rfg;        /* may be NULL */
 
   if (arg_vn && strcmp (arg_vn, "*"))
     {
@@ -3167,7 +3174,41 @@ parse_deleter_args (
           rcdarg->l2o.flags |= RFAPI_L2O_LNI;
         }
     }
-  return 0;
+  if (arg_rd)
+    {
+      if (!str2prefix_rd (arg_rd, &rcdarg->rd))
+        {
+          vty_out (vty, "Malformed RD \"%s\"%s",
+                   arg_rd, VTY_NEWLINE);
+          return rc;
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+static int
+parse_deleter_tokens (
+  struct vty                           *vty,
+  struct bgp                            *bgp,
+  struct cmd_token                     *carg_prefix,
+  struct cmd_token                     *carg_vn,
+  struct cmd_token                     *carg_un,
+  struct cmd_token                     *carg_l2addr,
+  struct cmd_token                     *carg_vni,
+  struct cmd_token                     *carg_rd,
+  struct rfapi_nve_group_cfg            *arg_rfg,
+  struct rfapi_local_reg_delete_arg    *rcdarg)
+{
+  const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
+  const char *arg_vn     = carg_vn ? carg_vn->arg : NULL;
+  const char *arg_un     = carg_un ? carg_un->arg : NULL;
+  const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
+  const char *arg_vni    = carg_vni ? carg_vni->arg : NULL;
+  const char *arg_rd     = carg_rd ? carg_rd->arg : NULL;
+  return parse_deleter_args (vty, bgp,arg_prefix, arg_vn, arg_un,
+                             arg_l2addr, arg_vni, arg_rd,
+                             arg_rfg, rcdarg);
 }
 
 static void
@@ -3271,51 +3312,37 @@ clear_vnc_responses (struct rfapi_local_reg_delete_arg *cda)
  * TBD need to count deleted prefixes and nves?
  *
  * ENXIO       BGP or VNC not configured
- */
+ */ 
 static int
-rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
+rfapiDeleteLocalPrefixesByRFD (struct rfapi_local_reg_delete_arg *cda,
+                               struct rfapi_descriptor *rfd)
 {
-  struct rfapi_ip_addr *pUn;    /* NULL = wildcard */
-  struct rfapi_ip_addr *pVn;    /* NULL = wildcard */
-  struct prefix *pPrefix;       /* NULL = wildcard */
+  struct rfapi_ip_addr *pUn;     /* NULL = wildcard */
+  struct rfapi_ip_addr *pVn;     /* NULL = wildcard */
+  struct prefix        *pPrefix; /* NULL = wildcard */
+  struct prefix_rd     *pPrd;    /* NULL = wildcard */
 
-  struct rfapi *h;
-  struct listnode *node;
-  struct rfapi_descriptor *rfd;
   struct rfapi_ip_prefix rprefix;
-  struct bgp *bgp_default = bgp_get_default ();
   struct rfapi_next_hop_entry *head = NULL;
   struct rfapi_next_hop_entry *tail = NULL;
-  struct rfapi_cfg *rfapi_cfg;
 
 #if DEBUG_L2_EXTRA
-    vnc_zlog_debug_verbose ("%s: entry", __func__);
+  vnc_zlog_debug_verbose ("%s: entry", __func__);
 #endif
 
-  if (!bgp_default)
-      return ENXIO;
-
-    pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
-    pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
-    pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
-
-    h = bgp_default->rfapi;
-    rfapi_cfg = bgp_default->rfapi_cfg;
-
-  if (!h || !rfapi_cfg)
-      return ENXIO;
+  pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
+  pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
+  pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
+  pPrd = (cda->rd.prefixlen == 64 ? &cda->rd : NULL);
 
   if (pPrefix)
     {
       rfapiQprefix2Rprefix (pPrefix, &rprefix);
     }
 
-#if DEBUG_L2_EXTRA
-  vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
-#endif
-
-  for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
+  do                            /* to preserve old code structure */
     {
+      struct rfapi *h=cda->bgp->rfapi;;
       struct rfapi_adb *adb;
       int rc;
       int deleted_from_this_nve;
@@ -3380,6 +3407,17 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
 #if DEBUG_L2_EXTRA
                     vnc_zlog_debug_verbose ("%s: adb=%p, prefix doesn't match, skipping",
                                 __func__, adb);
+#endif
+                    continue;
+                  }
+              }
+            if (pPrd) 
+              {
+                if (memcmp(pPrd->val, adb->u.s.prd.val, 8) != 0)
+                  {
+#if DEBUG_L2_EXTRA
+                    vnc_zlog_debug_verbose ("%s: adb=%p, RD doesn't match, skipping",
+                                __func__, adb);
 #endif
                     continue;
                   }
@@ -3422,47 +3460,43 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
 
         for (ALL_LIST_ELEMENTS_RO (adb_delete_list, node, adb))
           {
-
-            struct rfapi_vn_option vn1;
-            struct rfapi_vn_option vn2;
-            struct rfapi_vn_option *pVn;
             int this_advertisement_prefix_count;
+            struct rfapi_vn_option optary[3];
+            struct rfapi_vn_option *opt = NULL;
+            int                     cur_opt = 0;
 
             this_advertisement_prefix_count = 1;
 
             rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp);
 
+            memset (optary, 0, sizeof (optary));
+
             /* if mac addr present in advert,  make l2o vn option */
             if (adb->u.s.prefix_eth.family == AF_ETHERNET)
               {
-                memset (&vn1, 0, sizeof (vn1));
-                memset (&vn2, 0, sizeof (vn2));
-
-                vn1.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
-                vn1.v.l2addr.macaddr = adb->u.s.prefix_eth.u.prefix_eth;
-
-                /*
-                 * use saved RD value instead of trying to invert
-                 * complex L2-style RD computation in rfapi_register()
-                 */
-                vn2.type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
-                vn2.v.internal_rd = adb->u.s.prd;
-
-                vn1.next = &vn2;
-
-                pVn = &vn1;
+                if (opt != NULL)
+                  opt->next = &optary[cur_opt];
+                opt = &optary[cur_opt++];
+                opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
+                opt->v.l2addr.macaddr = adb->u.s.prefix_eth.u.prefix_eth;
                 ++this_advertisement_prefix_count;
               }
-            else
-              {
-                pVn = NULL;
-              }
+            /*
+             * use saved RD value instead of trying to invert
+             * complex RD computation in rfapi_register()
+             */
+            if (opt != NULL)
+              opt->next = &optary[cur_opt];
+            opt = &optary[cur_opt++];
+            opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+            opt->v.internal_rd = adb->u.s.prd;
 
 #if DEBUG_L2_EXTRA
             vnc_zlog_debug_verbose ("%s: ipN killing reg from adb %p ", __func__, adb);
 #endif
 
-            rc = rfapi_register (rfd, &rp, 0, NULL, pVn, RFAPI_REGISTER_KILL);
+            rc = rfapi_register (rfd, &rp, 0, NULL, 
+                                 (cur_opt ? optary : NULL), RFAPI_REGISTER_KILL);
             if (!rc)
               {
                 cda->pfx_count += this_advertisement_prefix_count;
@@ -3588,11 +3622,44 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
               skiplist_insert (cda->nves, hap, hap);
             }
         }
-    }
+    } while (0);                /*  to preserve old code structure */
 
   return 0;
 }
 
+static int
+rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
+{
+  int rc = 0;
+
+  if (cda->rfg)
+    {
+      if (cda->rfg->rfd)        /* if not open, nothing to delete */
+        rc = rfapiDeleteLocalPrefixesByRFD (cda, cda->rfg->rfd);
+    }
+  else
+    {
+      struct bgp *bgp = cda->bgp;
+      struct rfapi *h;
+      struct rfapi_cfg *rfapi_cfg;
+
+      struct listnode *node;
+      struct rfapi_descriptor *rfd;
+      if (!bgp)
+        return ENXIO;
+      h = bgp->rfapi;
+      rfapi_cfg = bgp->rfapi_cfg;
+      if (!h || !rfapi_cfg)
+        return ENXIO;
+      vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
+      for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
+        {
+          rc = rfapiDeleteLocalPrefixesByRFD (cda, rfd);
+        }
+    }
+  return rc;
+}
+
 /*
  * clear_vnc_prefix
  *
@@ -3608,6 +3675,8 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
   struct prefix *pVN = NULL;
   struct prefix *pPrefix = NULL;
 
+  struct rfapi_import_table *it = NULL;
+
   /*
    * Delete matching remote prefixes in holddown
    */
@@ -3625,7 +3694,11 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
     {
       pPrefix = &cda->prefix;
     }
-  rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix,
+  if (cda->rfg)
+    {
+      it = cda->rfg->rfapi_import_table;
+    }
+  rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix, it,
                              0, 1, &cda->remote_active_pfx_count,
                              &cda->remote_active_nve_count,
                              &cda->remote_holddown_pfx_count,
@@ -3710,7 +3783,7 @@ DEFUN (clear_vnc_nve_all,
   struct rfapi_local_reg_delete_arg cda;
   int rc;
 
-  if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, &cda)))
+  if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
     return rc;
 
   cda.vty = vty;
@@ -3743,7 +3816,7 @@ DEFUN (clear_vnc_nve_vn_un,
   int rc;
 
   if ((rc =
-       parse_deleter_args (vty, NULL, argv[4], argv[6], NULL, NULL, &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, argv[4], argv[6], NULL, NULL, NULL, NULL, &cda)))
     return rc;
 
   cda.vty = vty;
@@ -3776,7 +3849,7 @@ DEFUN (clear_vnc_nve_un_vn,
   int rc;
 
   if ((rc =
-       parse_deleter_args (vty, NULL, argv[6], argv[4], NULL, NULL, &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, argv[6], argv[4], NULL, NULL, NULL, NULL, &cda)))
     return rc;
 
   cda.vty = vty;
@@ -3804,7 +3877,7 @@ DEFUN (clear_vnc_nve_vn,
   struct rfapi_local_reg_delete_arg cda;
   int rc;
 
-  if ((rc = parse_deleter_args (vty, NULL, argv[4], NULL, NULL, NULL, &cda)))
+  if ((rc = parse_deleter_tokens (vty, NULL, NULL, argv[4], NULL, NULL, NULL, NULL, NULL, &cda)))
     return rc;
 
   cda.vty = vty;
@@ -3831,7 +3904,7 @@ DEFUN (clear_vnc_nve_un,
   struct rfapi_local_reg_delete_arg cda;
   int rc;
 
-  if ((rc = parse_deleter_args (vty, NULL, NULL, argv[6], NULL, NULL, &cda)))
+  if ((rc = parse_deleter_tokens (vty, NULL, NULL, NULL, argv[6], NULL, NULL, NULL, NULL, &cda)))
     return rc;
 
   cda.vty = vty;
@@ -3874,7 +3947,7 @@ DEFUN (clear_vnc_prefix_vn_un,
   int rc;
 
   if ((rc =
-       parse_deleter_args (vty, argv[3], argv[5], argv[7], NULL, NULL, &cda)))
+       parse_deleter_tokens (vty, NULL, argv[3], argv[5], argv[7], NULL, NULL, NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -3904,7 +3977,7 @@ DEFUN (clear_vnc_prefix_un_vn,
   int rc;
 
   if ((rc =
-       parse_deleter_args (vty, argv[3], argv[7], argv[5], NULL, NULL, &cda)))
+       parse_deleter_tokens (vty, NULL, argv[3], argv[7], argv[5], NULL, NULL, NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -3930,7 +4003,7 @@ DEFUN (clear_vnc_prefix_un,
   int rc;
 
   if ((rc =
-       parse_deleter_args (vty, argv[3], NULL, argv[5], NULL, NULL, &cda)))
+       parse_deleter_tokens (vty, NULL, argv[3], NULL, argv[5], NULL, NULL, NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -3956,7 +4029,7 @@ DEFUN (clear_vnc_prefix_vn,
   int rc;
 
   if ((rc =
-       parse_deleter_args (vty, argv[3], argv[5], NULL, NULL, NULL, &cda)))
+       parse_deleter_tokens (vty, NULL, argv[3], argv[5], NULL, NULL, NULL, NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -3978,7 +4051,7 @@ DEFUN (clear_vnc_prefix_all,
   struct rfapi_local_reg_delete_arg cda;
   int rc;
 
-  if ((rc = parse_deleter_args (vty, argv[3], NULL, NULL, NULL, NULL, &cda)))
+  if ((rc = parse_deleter_tokens (vty, NULL, argv[3], NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4020,8 +4093,8 @@ DEFUN (clear_vnc_mac_vn_un,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, NULL, argv[7], argv[9], argv[3], argv[5],
-                           &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, argv[7], argv[9], argv[3], argv[5],
+                           NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4054,8 +4127,8 @@ DEFUN (clear_vnc_mac_un_vn,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, NULL, argv[9], argv[7], argv[3], argv[5],
-                           &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, argv[9], argv[7], argv[3], argv[5],
+                           NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4084,7 +4157,7 @@ DEFUN (clear_vnc_mac_un,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, NULL, NULL, argv[7], argv[3], argv[5], &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, NULL, argv[7], argv[3], argv[5], NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4113,7 +4186,7 @@ DEFUN (clear_vnc_mac_vn,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, NULL, argv[7], NULL, argv[3], argv[5], &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, argv[7], NULL, argv[3], argv[5], NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4139,7 +4212,7 @@ DEFUN (clear_vnc_mac_all,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, NULL, NULL, NULL, argv[3], argv[5], &cda)))
+       parse_deleter_tokens (vty, NULL, NULL, NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4180,8 +4253,8 @@ DEFUN (clear_vnc_mac_vn_un_prefix,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, argv[11], argv[7], argv[9], argv[3], argv[5],
-                           &cda)))
+       parse_deleter_tokens (vty, NULL, argv[11], argv[7], argv[9], argv[3], argv[5],
+                           NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4222,8 +4295,8 @@ DEFUN (clear_vnc_mac_un_vn_prefix,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, argv[11], argv[9], argv[7], argv[3], argv[5],
-                           &cda)))
+       parse_deleter_tokens (vty, NULL, argv[11], argv[9], argv[7], argv[3], argv[5],
+                           NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4256,8 +4329,8 @@ DEFUN (clear_vnc_mac_un_prefix,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, argv[9], NULL, argv[7], argv[3], argv[5],
-                           &cda)))
+       parse_deleter_tokens (vty, NULL, argv[9], NULL, argv[7], argv[3], argv[5],
+                           NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4290,8 +4363,8 @@ DEFUN (clear_vnc_mac_vn_prefix,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, argv[9], argv[7], NULL, argv[3], argv[5],
-                           &cda)))
+       parse_deleter_tokens (vty, NULL, argv[9], argv[7], NULL, argv[3], argv[5],
+                           NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4320,7 +4393,7 @@ DEFUN (clear_vnc_mac_all_prefix,
 
   /* pfx vn un L2 VNI */
   if ((rc =
-       parse_deleter_args (vty, argv[7], NULL, NULL, argv[3], argv[5], &cda)))
+       parse_deleter_tokens (vty, NULL, argv[7], NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
     return rc;
   cda.vty = vty;
   clear_vnc_prefix (&cda);
@@ -4928,6 +5001,361 @@ notcfg:
   return CMD_WARNING;
 }
 
+/************************************************************************
+ *             Add prefix with vrf
+ *
+ * add [vrf <vrf-name>] prefix <prefix>
+ *     [rd <value>] [label <value>] [local-preference <0-4294967295>]
+ ************************************************************************/
+static int
+vnc_add_vrf_prefix (struct vty *vty,
+                    const char *arg_vrf,
+                    const char *arg_prefix,
+                    const char *arg_rd,     /* optional */
+                    const char *arg_label,  /* optional */
+                    const char *arg_pref)   /* optional */
+{
+  struct bgp                 *bgp;
+  struct rfapi_nve_group_cfg *rfg;
+  struct prefix               pfx;
+  struct rfapi_ip_prefix      rpfx;
+  uint32_t                    pref = 0;
+  struct rfapi_vn_option      optary[3];
+  struct rfapi_vn_option      *opt = NULL;
+  int                         cur_opt = 0;
+
+  bgp = bgp_get_default (); /* assume main instance for now */
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (!bgp->rfapi || !bgp->rfapi_cfg)
+    {
+      vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rfg = bgp_rfapi_cfg_match_byname (bgp,  arg_vrf, RFAPI_GROUP_CFG_VRF);
+  /* arg checks */
+  if (!rfg)
+    {
+      vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
+               arg_vrf, VTY_NEWLINE);
+          return CMD_WARNING;
+    }
+  if (!rfg->rt_export_list || !rfg->rfapi_import_table)
+    {
+      vty_out (vty, "VRF \"%s\" is missing RT import/export RT configuration.%s",
+               arg_vrf, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (!rfg->rd.family && !arg_rd)
+    {
+      vty_out (vty, "VRF \"%s\" isn't configured with an RD, so RD must be provided.%s",
+               arg_vrf, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (rfg->label > MPLS_LABEL_MAX && !arg_label)
+    {
+      vty_out (vty, "VRF \"%s\" isn't configured with a default labels, so a label must be provided.%s",
+               arg_vrf, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (!str2prefix (arg_prefix, &pfx))
+    {
+      vty_out (vty, "Malformed prefix \"%s\"%s",
+               arg_prefix, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  rfapiQprefix2Rprefix (&pfx, &rpfx);
+  memset (optary, 0, sizeof (optary));
+  if (arg_rd)
+    {
+      if (opt != NULL)
+        opt->next = &optary[cur_opt];
+      opt = &optary[cur_opt++];
+      opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+      if (!str2prefix_rd (arg_rd, &opt->v.internal_rd))
+        {
+          vty_out (vty, "Malformed RD \"%s\"%s",
+                   arg_rd, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+  if (rfg->label <= MPLS_LABEL_MAX || arg_label)
+    {
+      struct rfapi_l2address_option    *l2o;
+      if (opt != NULL)
+        opt->next = &optary[cur_opt];
+      opt = &optary[cur_opt++];
+      opt->type  = RFAPI_VN_OPTION_TYPE_L2ADDR;
+      l2o =  &opt->v.l2addr;
+      if (arg_label)
+        {
+          int32_t label;
+          VTY_GET_INTEGER_RANGE ("Label value", label, arg_label, 0, MPLS_LABEL_MAX);
+          l2o->label = label;
+        }
+      else
+        l2o->label = rfg->label;
+    }
+  if (arg_pref)
+    {
+      char *endptr = NULL;
+      pref = strtoul (arg_pref, &endptr, 10);
+      if (*endptr != '\0')
+        {
+          vty_out (vty, "%% Invalid local-preference value \"%s\"%s", arg_pref, VTY_NEWLINE);
+          return CMD_WARNING;
+         }
+    }
+  rpfx.cost = 255 - (pref & 255) ;
+  if (rfg->rfd == NULL)         /* need new rfapi_handle */
+    {
+      /* based on rfapi_open */
+      struct rfapi_descriptor *rfd;
+      rfd = XCALLOC (MTYPE_RFAPI_DESC, sizeof (struct rfapi_descriptor));
+      rfd->bgp = bgp;
+      rfg->rfd = rfd;
+      /* leave most fields empty as will get from (dynamic) config when needed */
+      rfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS;
+      rfd->cookie = rfg;
+      if (rfg->vn_prefix.family &&
+          !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF))
+        {
+          rfapiQprefix2Raddr(&rfg->vn_prefix, &rfd->vn_addr);
+        }
+      else
+        {
+          memset(&rfd->vn_addr, 0, sizeof(struct rfapi_ip_addr));
+          rfd->vn_addr.addr_family = AF_INET;
+          rfd->vn_addr.addr.v4 = bgp->router_id;
+        }
+      rfd->un_addr = rfd->vn_addr; /* sigh, need something in UN for lookups */
+      vnc_zlog_debug_verbose ("%s: Opening RFD for VRF %s",
+                              __func__, rfg->name);
+      rfapi_init_and_open(bgp, rfd, rfg);
+    }
+
+  if (!rfapi_register (rfg->rfd, &rpfx, RFAPI_INFINITE_LIFETIME, NULL,
+                       (cur_opt ? optary : NULL), RFAPI_REGISTER_ADD))
+    {
+      struct rfapi_next_hop_entry *head = NULL;
+      struct rfapi_next_hop_entry *tail = NULL;
+      struct rfapi_vn_option *vn_opt_new;
+
+      vnc_zlog_debug_verbose ("%s: rfapi_register succeeded", __func__);
+
+      if (bgp->rfapi->rfp_methods.local_cb)
+        {
+          struct rfapi_descriptor *r = (struct rfapi_descriptor *) rfg->rfd;
+          vn_opt_new = rfapi_vn_options_dup (opt);
+
+          rfapiAddDeleteLocalRfpPrefix (&r->un_addr, &r->vn_addr, &rpfx,
+                                        1, RFAPI_INFINITE_LIFETIME,
+                                        vn_opt_new, &head, &tail);
+          if (head)
+            {
+              bgp->rfapi->flags |= RFAPI_INCALLBACK;
+              (*bgp->rfapi->rfp_methods.local_cb) (head, r->cookie);
+              bgp->rfapi->flags &= ~RFAPI_INCALLBACK;
+            }
+          head = tail = NULL;
+        }
+      vnc_zlog_debug_verbose ("%s completed, count=%d/%d",  __func__,
+                              rfg->rfapi_import_table->local_count[AFI_IP],
+                              rfg->rfapi_import_table->local_count[AFI_IP6]);
+      return CMD_SUCCESS;
+    }
+
+  vnc_zlog_debug_verbose ("%s: rfapi_register failed", __func__);
+  vty_out (vty, "Add failed.%s", VTY_NEWLINE);
+  return CMD_WARNING;
+}
+
+DEFUN (add_vrf_prefix_rd_label_pref,
+       add_vrf_prefix_rd_label_pref_cmd,
+      "add vrf NAME prefix <A.B.C.D/M|X:X::X:X/M> [rd ASN:nn_or_IP-address] [label (0-1048575)] [preference (0-4294967295)]",
+       "Add\n"
+       "To a VRF\n"
+       "VRF name\n"
+       "Add/modify prefix related information\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "Override configured VRF Route Distinguisher\n"
+       "<as-number>:<number> or <ip-address>:<number>\n"
+       "Override configured VRF label"
+       "Label Value <0-1048575>\n"
+       "Set advertised local preference\n"
+       "local preference (higher=more preferred)\n")
+{
+  char *arg_vrf    = argv[2]->arg;
+  char *arg_prefix = argv[4]->arg;
+  char *arg_rd     = NULL;      /* optional */
+  char *arg_label  = NULL;      /* optional */
+  char *arg_pref   = NULL;      /* optional */
+  int  pargc = 5;
+  argc--;                        /* don't parse argument */
+  while (pargc < argc) 
+    {
+      switch (argv[pargc++]->arg[0])
+        {
+        case 'r':
+          arg_rd    = argv[pargc]->arg;
+          break;
+        case 'l':
+          arg_label = argv[pargc]->arg;
+          break;
+        case 'p':
+          arg_pref  = argv[pargc]->arg;
+          break;
+        default:
+          break;
+        }
+      pargc ++;
+    }
+  
+  return vnc_add_vrf_prefix (vty, arg_vrf, arg_prefix, arg_rd, arg_label, arg_pref);
+}
+
+/************************************************************************
+ *             del prefix with vrf
+ *
+ * clear [vrf <vrf-name>] prefix <prefix> [rd <value>]
+ ************************************************************************/
+static int
+rfapi_cfg_group_it_count(struct rfapi_nve_group_cfg *rfg)
+{
+  int count = 0;
+  afi_t afi = AFI_MAX;
+  while (afi-- > 0)
+    {
+      count += rfg->rfapi_import_table->local_count[afi];
+    }
+  return count;
+}
+
+static void
+clear_vnc_vrf_closer (struct rfapi_nve_group_cfg *rfg)
+{
+  struct rfapi_descriptor *rfd = rfg->rfd;
+  afi_t                    afi;
+
+  if (rfd == NULL)
+    return;
+  /* check if IT is empty */
+  for (afi = 0; 
+       afi < AFI_MAX && rfg->rfapi_import_table->local_count[afi] == 0; 
+       afi++);
+
+  if (afi == AFI_MAX)
+    {
+      vnc_zlog_debug_verbose ("%s: closing RFD for VRF %s",
+                              __func__, rfg->name);
+      rfg->rfd = NULL;
+      rfapi_close(rfd);
+    }
+  else
+    {
+      vnc_zlog_debug_verbose ("%s: VRF %s afi=%d count=%d",
+                              __func__, rfg->name, afi, 
+                              rfg->rfapi_import_table->local_count[afi]);
+    }
+}
+
+static int
+vnc_clear_vrf (struct vty *vty,
+               struct bgp *bgp,
+               const char *arg_vrf,
+               const char *arg_prefix, /* NULL = all */
+               const char *arg_rd)     /* optional */
+{
+  struct rfapi_nve_group_cfg        *rfg;
+  struct rfapi_local_reg_delete_arg  cda;
+  int                                rc;
+  int                                start_count;
+
+  if (bgp == NULL)
+    bgp = bgp_get_default (); /* assume main instance for now */
+  if (!bgp)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (!bgp->rfapi || !bgp->rfapi_cfg)
+    {
+      vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  rfg = bgp_rfapi_cfg_match_byname (bgp,  arg_vrf, RFAPI_GROUP_CFG_VRF);
+  /* arg checks */
+  if (!rfg)
+    {
+      vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
+               arg_vrf, VTY_NEWLINE);
+          return CMD_WARNING;
+    }
+  rc = parse_deleter_args (vty, bgp, arg_prefix, NULL, NULL, NULL, NULL,
+                           arg_rd, rfg, &cda);
+  if (rc != CMD_SUCCESS)        /* parse error */
+    return rc;
+
+  start_count = rfapi_cfg_group_it_count(rfg);
+  clear_vnc_prefix (&cda);
+  clear_vnc_vrf_closer (rfg);
+  vty_out (vty, "Cleared %u out of %d prefixes.%s", 
+           cda.pfx_count, start_count, VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+DEFUN (clear_vrf_prefix_rd,
+       clear_vrf_prefix_rd_cmd,
+       "clear vrf NAME [prefix <A.B.C.D/M|X:X::X:X/M>] [rd ASN:nn_or_IP-address]",
+       "Clear stored data\n"
+       "From a VRF\n"
+       "VRF name\n"
+       "Prefix related information\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "Specific VRF Route Distinguisher\n"
+       "<as-number>:<number> or <ip-address>:<number>\n")
+{
+  char *arg_vrf    = argv[2]->arg;
+  char *arg_prefix = NULL;       /* optional */
+  char *arg_rd     = NULL;       /* optional */
+  int  pargc = 3;
+  argc--;                       /* don't check parameter */
+  while (pargc < argc) 
+    {
+      switch (argv[pargc++]->arg[0])
+        {
+        case 'r':
+          arg_rd     = argv[pargc]->arg;
+          break;
+        case 'p':
+          arg_prefix = argv[pargc]->arg;
+          break;
+        default:
+          break;
+        }
+      pargc ++;
+    }
+  return vnc_clear_vrf (vty, NULL, arg_vrf, arg_prefix, arg_rd);
+}
+
+DEFUN (clear_vrf_all,
+       clear_vrf_all_cmd,
+       "clear vrf NAME all",
+       "Clear stored data\n"
+       "From a VRF\n"
+       "VRF name\n"
+       "All prefixes\n")
+{
+  char *arg_vrf    = argv[2]->arg;
+  return vnc_clear_vrf (vty, NULL, arg_vrf, NULL, NULL);
+}
+
 void rfapi_vty_init ()
 {
   install_element (ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd);
@@ -4951,6 +5379,8 @@ void rfapi_vty_init ()
   install_element (ENABLE_NODE, &add_vnc_mac_vni_life_cmd);
   install_element (ENABLE_NODE, &add_vnc_mac_vni_cmd);
 
+  install_element (ENABLE_NODE, &add_vrf_prefix_rd_label_pref_cmd);
+
   install_element (ENABLE_NODE, &clear_vnc_nve_all_cmd);
   install_element (ENABLE_NODE, &clear_vnc_nve_vn_un_cmd);
   install_element (ENABLE_NODE, &clear_vnc_nve_un_vn_cmd);
@@ -4975,6 +5405,9 @@ void rfapi_vty_init ()
   install_element (ENABLE_NODE, &clear_vnc_mac_vn_prefix_cmd);
   install_element (ENABLE_NODE, &clear_vnc_mac_all_prefix_cmd);
 
+  install_element (ENABLE_NODE, &clear_vrf_prefix_rd_cmd);
+  install_element (ENABLE_NODE, &clear_vrf_all_cmd);
+
   install_element (ENABLE_NODE, &vnc_clear_counters_cmd);
 
   install_element (VIEW_NODE, &vnc_show_summary_cmd);
index 6294e994e70c7ca451cbc3d13ab45e9c4b9204fc..4ac1d1abe5ffb492b7ef993fac9be198ba3e339b 100644 (file)
@@ -741,6 +741,7 @@ node_parent ( enum node_type node )
     case BGP_VPNV6_NODE:
     case BGP_ENCAP_NODE:
     case BGP_ENCAPV6_NODE:
+    case BGP_VRF_POLICY_NODE:
     case BGP_VNC_DEFAULTS_NODE:
     case BGP_VNC_NVE_GROUP_NODE:
     case BGP_VNC_L2_GROUP_NODE:
@@ -1106,6 +1107,7 @@ cmd_exit (struct vty *vty)
     case BGP_VPNV6_NODE:
     case BGP_ENCAP_NODE:
     case BGP_ENCAPV6_NODE:
+    case BGP_VRF_POLICY_NODE:
     case BGP_VNC_DEFAULTS_NODE:
     case BGP_VNC_NVE_GROUP_NODE:
     case BGP_VNC_L2_GROUP_NODE:
@@ -1169,6 +1171,7 @@ DEFUN (config_end,
     case BGP_NODE:
     case BGP_ENCAP_NODE:
     case BGP_ENCAPV6_NODE:
+    case BGP_VRF_POLICY_NODE:
     case BGP_VNC_DEFAULTS_NODE:
     case BGP_VNC_NVE_GROUP_NODE:
     case BGP_VNC_L2_GROUP_NODE:
index 1e1698fc7d123908f65365a6e7bcddbd643a18b9..bc68cc0c849d329bf00aba21528e2e8354dd52fe 100644 (file)
@@ -99,6 +99,7 @@ enum node_type
   BGP_IPV6M_NODE,               /* BGP IPv6 multicast address family. */
   BGP_ENCAP_NODE,               /* BGP ENCAP SAFI */
   BGP_ENCAPV6_NODE,             /* BGP ENCAP SAFI */
+  BGP_VRF_POLICY_NODE,          /* BGP VRF policy */
   BGP_VNC_DEFAULTS_NODE,       /* BGP VNC nve defaults */
   BGP_VNC_NVE_GROUP_NODE,      /* BGP VNC nve group */
   BGP_VNC_L2_GROUP_NODE,       /* BGP VNC L2 group */
index a435706d1f9df34aec35ceb7a727ba7064409981..9413d003efac8383fa76274b094bbdd7da97e4d1 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -742,6 +742,7 @@ vty_end_config (struct vty *vty)
     case BGP_VPNV6_NODE:
     case BGP_ENCAP_NODE:
     case BGP_ENCAPV6_NODE:
+    case BGP_VRF_POLICY_NODE:
     case BGP_VNC_DEFAULTS_NODE:
     case BGP_VNC_NVE_GROUP_NODE:
     case BGP_VNC_L2_GROUP_NODE:
index 50677b56857da616e71162a3343f78ff85ebd010..51b5091c5753c12b683a9f670a463fc865e62afa 100644 (file)
@@ -312,6 +312,10 @@ vtysh_execute_func (const char *line, int pager)
        {
          vtysh_execute("exit-address-family");
        }
+      else if (saved_node == BGP_VRF_POLICY_NODE && (tried == 1))
+       {
+         vtysh_execute("exit-vrf-policy");
+       }
       else if ((saved_node == BGP_VNC_DEFAULTS_NODE
            || saved_node == BGP_VNC_NVE_GROUP_NODE
            || saved_node == BGP_VNC_L2_GROUP_NODE) && (tried == 1))
@@ -963,6 +967,11 @@ static struct cmd_node bgp_vnc_nve_group_node =
   "%s(config-router-vnc-nve-group)# "
 };
 
+static struct cmd_node bgp_vrf_policy_node = {
+  BGP_VRF_POLICY_NODE,
+  "%s(config-router-vrf-policy)# "
+};
+
 static struct cmd_node bgp_vnc_l2_group_node =
 {
   BGP_VNC_L2_GROUP_NODE,
@@ -1209,6 +1218,17 @@ DEFUNSH (VTYSH_BGPD,
   return CMD_SUCCESS;
 }
 
+DEFUNSH (VTYSH_BGPD,
+         vnc_vrf_policy,
+         vnc_vrf_policy_cmd,
+         "vrf-policy NAME",
+         "Configure a VRF policy group\n"
+         "Group name\n")
+{
+  vty->node = BGP_VRF_POLICY_NODE;
+  return CMD_SUCCESS;
+}
+
 DEFUNSH (VTYSH_BGPD,
          vnc_l2_group,
          vnc_l2_group_cmd,
@@ -1481,6 +1501,7 @@ vtysh_exit (struct vty *vty)
     case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:
     case BGP_IPV6M_NODE:
+    case BGP_VRF_POLICY_NODE:
     case BGP_VNC_DEFAULTS_NODE:
     case BGP_VNC_NVE_GROUP_NODE:
     case BGP_VNC_L2_GROUP_NODE:
@@ -1560,6 +1581,17 @@ DEFUNSH (VTYSH_BGPD,
   return CMD_SUCCESS;
 }
 
+DEFUNSH (VTYSH_BGPD,
+        exit_vrf_policy,
+        exit_vrf_policy_cmd,
+        "exit-vrf-policy",
+        "Exit from VRF  configuration mode\n")
+{
+  if (vty->node == BGP_VRF_POLICY_NODE)
+    vty->node = BGP_NODE;
+  return CMD_SUCCESS;
+}
+
 DEFUNSH (VTYSH_RIPD,
         vtysh_exit_ripd,
         vtysh_exit_ripd_cmd,
@@ -3042,6 +3074,7 @@ vtysh_init_vty (void)
   install_node (&bgp_ipv4m_node, NULL);
   install_node (&bgp_ipv6_node, NULL);
   install_node (&bgp_ipv6m_node, NULL);
+  install_node (&bgp_vrf_policy_node, NULL);
   install_node (&bgp_vnc_defaults_node, NULL);
   install_node (&bgp_vnc_nve_group_node, NULL);
   install_node (&bgp_vnc_l2_group_node, NULL);
@@ -3079,6 +3112,7 @@ vtysh_init_vty (void)
   vtysh_install_default (BGP_IPV6_NODE);
   vtysh_install_default (BGP_IPV6M_NODE);
 #if ENABLE_BGP_VNC
+  vtysh_install_default (BGP_VRF_POLICY_NODE);
   vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
   vtysh_install_default (BGP_VNC_NVE_GROUP_NODE);
   vtysh_install_default (BGP_VNC_L2_GROUP_NODE);
@@ -3150,6 +3184,8 @@ vtysh_init_vty (void)
   install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
 #if defined (ENABLE_BGP_VNC)
+  install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd);
   install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd);
@@ -3191,6 +3227,7 @@ vtysh_init_vty (void)
   install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
   install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
+  install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
   install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
@@ -3239,6 +3276,7 @@ vtysh_init_vty (void)
   install_element (BGP_NODE, &address_family_encapv4_cmd);
   install_element (BGP_NODE, &address_family_encapv6_cmd);
 #if defined(ENABLE_BGP_VNC)
+  install_element (BGP_NODE, &vnc_vrf_policy_cmd);
   install_element (BGP_NODE, &vnc_defaults_cmd);
   install_element (BGP_NODE, &vnc_nve_group_cmd);
   install_element (BGP_NODE, &vnc_l2_group_cmd);
@@ -3256,6 +3294,7 @@ vtysh_init_vty (void)
   install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
   install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
 
+  install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
   install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
   install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);
   install_element (BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd);