A new subnode under router bgp command has been created: vrf <>. This enhancement permits creating a VRF instance specific to VRF. Then it permits setting specific configuration to vrf entity. This is the case for route distinguisher, but also route target. vrf <NAME> rd <route distinguisher name> no rd <RD name> rt import <RT list> rt export <RT list> rt both <RT list> no rt import <> no rt export <> no rt both <> exit no vrf <NAME>
Currently, this is necessary to manually set route distinguisher. Signed-off-by: Philippe Guibert <philippe.guib...@6wind.com> --- bgpd/bgp_route.c | 3 + bgpd/bgp_vty.c | 252 ++++++++++++++++++++++++++++++++++++++----------------- bgpd/bgpd.c | 126 ++++++++++++++++++++++------ bgpd/bgpd.h | 14 +++- 4 files changed, 291 insertions(+), 104 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index eb0c9e50094f..c4236fab481b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1528,6 +1528,9 @@ bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, void bgp_vrf_clean_tables (struct bgp_vrf *vrf) { afi_t afi; + + if (vrf->rib == NULL || vrf->route == NULL) + return; for (afi = AFI_IP; afi < AFI_MAX; afi++) { struct bgp_info *ri, *ri_next; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 63a7b5bfdcf6..4080438b06a0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9893,57 +9893,86 @@ bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, DEFUN (bgp_vrf, bgp_vrf_cmd, - "vrf rd WORD", - "BGP VPN VRF\n" - "Route Distinguisher\n" - "Route Distinguisher\n" + "vrf WORD", + "BGP VRF\n" + "VRF Name\n" ) { struct bgp *bgp = vty->index; struct bgp_vrf *vrf; - struct prefix_rd prd; + if ( (vrf = bgp_vrf_lookup_per_name (bgp, argv[0], 1)) == NULL) + return CMD_ERR_NO_MATCH; + vty->index_sub = vrf; + vty->node = BGP_VRF_NODE; - if (! str2prefix_rd (argv[0], &prd)) - { - vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } + return CMD_SUCCESS; +} +DEFUN (no_bgp_vrf, + no_bgp_vrf_cmd, + "no vrf WORD", + NO_STR + "BGP VRF\n" + "VRF Name\n" +) +{ + struct bgp *bgp = vty->index; + struct bgp_vrf *vrf; - vrf = bgp_vrf_lookup (bgp, &prd); - if (vrf) + vrf = bgp_vrf_lookup_per_name (bgp, argv[0], 0); + if (! vrf) { - vty_out (vty, "%% VRF with RD '%s' already exists%s", argv[0], VTY_NEWLINE); + vty_out (vty, "%% No VRF with name '%s'%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } + bgp_vrf_delete (vrf); + return CMD_SUCCESS; +} - bgp_vrf_create (bgp, &prd); +DEFUN (exit_bgp_vrf, + exit_bgp_vrf_cmd, + "exit-bgp-vrf", + "Exit from BGP vrf configuration mode\n") +{ + if (vty->node == BGP_VRF_NODE) + vty->node = BGP_NODE; return CMD_SUCCESS; } -DEFUN (bgp_vrf_exports, - bgp_vrf_exports_cmd, - "vrf rd WORD exports .LINE", - "BGP VPN VRF\n" +DEFUN (bgp_vrf_rd, + bgp_vrf_rd_cmd, + "rd WORD", "Route Distinguisher\n" - "Route Distinguisher\n" - "Export RT values\n" - "Export RT values\n" + "Route Distinguisher Name\n" ) { struct bgp *bgp = vty->index; - struct bgp_vrf *vrf; + struct bgp_vrf *vrf = vty->index_sub; struct prefix_rd prd; - struct ecommunity *ecom = NULL; - int fail = 0, i; - char *rts = NULL, *rts_ptr; if (! str2prefix_rd (argv[0], &prd)) { vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE); - fail++; + return CMD_WARNING; } + bgp_vrf_update_rd (bgp, vrf, &prd); + return CMD_SUCCESS; +} + +DEFUN (bgp_vrf_rt_export, + bgp_vrf_rt_export_cmd, + "rt export .LINE", + "Route Target\n" + "Export RT values\n" + "Export RT values\n" +) +{ + struct bgp_vrf *vrf = vty->index_sub; + struct ecommunity *ecom = NULL; + int fail = 0, i; + char *rts = NULL, *rts_ptr; + /* forge export list */ - i = 1; + i = 0; rts = XCALLOC(MTYPE_TMP,2048); rts_ptr = rts; while(i < argc) @@ -9963,44 +9992,27 @@ DEFUN (bgp_vrf_exports, if (fail) return CMD_WARNING; - vrf = bgp_vrf_lookup (bgp, &prd); - if (! vrf) - { - ecommunity_free (&ecom); - vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - ecom = ecommunity_intern (ecom); bgp_vrf_rt_export_set (vrf, ecom); ecommunity_unintern (&ecom); return CMD_SUCCESS; } -DEFUN (bgp_vrf_imports, - bgp_vrf_imports_cmd, - "vrf rd WORD imports .LINE", - "BGP VPN VRF\n" - "Route Distinguisher\n" - "Route Distinguisher\n" +DEFUN (bgp_vrf_rt_import, + bgp_vrf_rt_import_cmd, + "rt import .LINE", + "Route Target\n" "Import RT values\n" "Import RT values\n" ) { - struct bgp *bgp = vty->index; - struct bgp_vrf *vrf; - struct prefix_rd prd; + struct bgp_vrf *vrf = vty->index_sub; struct ecommunity *ecom = NULL; int fail = 0, i; char *rts = NULL, *rts_ptr; - if (! str2prefix_rd (argv[0], &prd)) - { - vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE); - fail++; - } /* forge export list */ - i = 1; + i = 0; rts = XCALLOC(MTYPE_TMP,2048); rts_ptr = rts; while(i < argc) @@ -10020,46 +10032,111 @@ DEFUN (bgp_vrf_imports, if (fail) return CMD_WARNING; - vrf = bgp_vrf_lookup (bgp, &prd); - if (! vrf) - { - ecommunity_free (&ecom); - vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - ecom = ecommunity_intern (ecom); bgp_vrf_rt_import_set (vrf, ecom); ecommunity_unintern (&ecom); return CMD_SUCCESS; } -DEFUN (no_bgp_vrf, - no_bgp_vrf_cmd, - "no vrf rd WORD", - NO_STR - "BGP VPN VRF\n" - "Route Distinguisher\n" - "Route Distinguisher\n" +DEFUN (bgp_vrf_rt_both, + bgp_vrf_rt_both_cmd, + "rt both .LINE", + "Route Target\n" + "Import and Export RT values\n" + "Import and Export RT values\n" ) { - struct bgp *bgp = vty->index; - struct bgp_vrf *vrf; - struct prefix_rd prd; + struct bgp_vrf *vrf = vty->index_sub; + struct ecommunity *ecom = NULL, *ecom1; + int fail = 0, i; + char *rts = NULL, *rts_ptr; - if (! str2prefix_rd (argv[0], &prd)) + /* forge export list */ + i = 0; + rts = XCALLOC(MTYPE_TMP,2048); + rts_ptr = rts; + while(i < argc) { - vty_out (vty, "%% Invalid RD '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; + rts_ptr += sprintf(rts_ptr, "rt %s ",argv[i]); + i++; } - - vrf = bgp_vrf_lookup (bgp, &prd); - if (! vrf) + /* convert list of ecoms string into ecom struct */ + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1); + if (! ecom) { - vty_out (vty, "%% No VRF with RD '%s'%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "%% Invalid RT '%s'%s", argv[1], VTY_NEWLINE); + fail++; } - bgp_vrf_delete (vrf); + if (rts) + XFREE (MTYPE_TMP, rts); + if (fail) + return CMD_WARNING; + + ecom1 = ecommunity_intern (ecom); + bgp_vrf_rt_import_set (vrf, ecom1); + ecommunity_unintern (&ecom1); + + ecom1 = ecommunity_intern (ecom); + bgp_vrf_rt_export_set (vrf, ecom1); + ecommunity_unintern (&ecom1); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_vrf_rt_import, + no_bgp_vrf_rt_import_cmd, + "no rt import", + NO_STR + "Route Target\n" + "Import values\n" +) +{ + struct bgp_vrf *vrf = vty->index_sub; + + bgp_vrf_rt_import_unset (vrf); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_vrf_rt_export, + no_bgp_vrf_rt_export_cmd, + "no rt export", + NO_STR + "Route Target\n" + "Export RT values\n" +) +{ + struct bgp_vrf *vrf = vty->index_sub; + + bgp_vrf_rt_export_unset (vrf); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_vrf_rt_both, + no_bgp_vrf_rt_both_cmd, + "no rt both", + NO_STR + "Route Target\n" + "Import and Export RT values\n" +) +{ + struct bgp_vrf *vrf = vty->index_sub; + + bgp_vrf_rt_export_unset (vrf); + bgp_vrf_rt_import_unset (vrf); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_vrf_rd, + no_bgp_vrf_rd_cmd, + "no rd WORD", + NO_STR + "BGP Route Distinguisher\n" + "Route Distinguisher\n" +) +{ + struct bgp_vrf *vrf = vty->index_sub; + + bgp_vrf_delete_rd (vrf); return CMD_SUCCESS; } @@ -10127,6 +10204,14 @@ static struct cmd_node bgp_encapv6_node = 1 }; +/* VRF node. */ +static struct cmd_node bgp_vrf_node = +{ + BGP_VRF_NODE, + "%s(bgp-vrf)# ", + 1 +}; + static void community_list_vty (void); void @@ -10142,6 +10227,7 @@ bgp_vty_init (void) install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_encap_node, NULL); install_node (&bgp_encapv6_node, NULL); + install_node (&bgp_vrf_node, NULL); /* Install default VTY commands to new nodes. */ install_default (BGP_NODE); @@ -10153,11 +10239,19 @@ bgp_vty_init (void) install_default (BGP_VPNV6_NODE); install_default (BGP_ENCAP_NODE); install_default (BGP_ENCAPV6_NODE); + install_default (BGP_VRF_NODE); install_element (BGP_NODE, &bgp_vrf_cmd); - install_element (BGP_NODE, &bgp_vrf_exports_cmd); - install_element (BGP_NODE, &bgp_vrf_imports_cmd); install_element (BGP_NODE, &no_bgp_vrf_cmd); + install_element (BGP_VRF_NODE, &bgp_vrf_rd_cmd); + install_element (BGP_VRF_NODE, &no_bgp_vrf_rd_cmd); + install_element (BGP_VRF_NODE, &bgp_vrf_rt_export_cmd); + install_element (BGP_VRF_NODE, &bgp_vrf_rt_import_cmd); + install_element (BGP_VRF_NODE, &bgp_vrf_rt_both_cmd); + install_element (BGP_VRF_NODE, &no_bgp_vrf_rt_import_cmd); + install_element (BGP_VRF_NODE, &no_bgp_vrf_rt_export_cmd); + install_element (BGP_VRF_NODE, &no_bgp_vrf_rt_both_cmd); + install_element (BGP_VRF_NODE, &exit_bgp_vrf_cmd); /* "bgp multiple-instance" commands. */ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5725730d9454..450371efd243 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2091,28 +2091,30 @@ bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub) } struct bgp_vrf * -bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd) +bgp_vrf_lookup_per_name (struct bgp *bgp, const char *name, int create) { + afi_t afi; struct listnode *node; struct bgp_vrf *vrf; + unsigned int len; + if (!name) + return NULL; + len = strlen(name); for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf)) - if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8)) - return vrf; - return NULL; -} - -struct bgp_vrf * -bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd) -{ - struct bgp_vrf *vrf; - afi_t afi; - - if ( (vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL) + { + if (strlen (vrf->name) != len) + continue; + if (0 == strcmp (vrf->name, name)) + break; + } + if (vrf || create == 0) + return vrf; + if ((vrf = XCALLOC (MTYPE_BGP_VRF, sizeof (struct bgp_vrf))) == NULL) return NULL; - vrf->bgp = bgp; - vrf->outbound_rd = *outbound_rd; + vrf->name = strdup (name); + vrf->flag |= BGP_VRF_RD_UNSET; for (afi = AFI_IP; afi < AFI_MAX; afi++) { @@ -2126,6 +2128,49 @@ bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd) return vrf; } +struct bgp_vrf * +bgp_vrf_lookup_per_rn (struct bgp *bgp, int afi, struct bgp_node *vrf_rn) +{ + struct listnode *node; + struct bgp_vrf *vrf; + + if(bgp_node_table (vrf_rn)->type != BGP_TABLE_VRF) + return NULL; + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf)) + if(vrf->rib[afi] == bgp_node_table (vrf_rn)) + { + return vrf; + } + return NULL; +} + +struct bgp_vrf * +bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd) +{ + struct listnode *node; + struct bgp_vrf *vrf; + + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf)) + if (!memcmp (outbound_rd->val, vrf->outbound_rd.val, 8)) + return vrf; + return NULL; +} + +struct bgp_vrf * +bgp_vrf_update_rd (struct bgp *bgp, struct bgp_vrf *vrf, struct prefix_rd *outbound_rd) +{ + if (!vrf) + { + char vrf_rd_str[RD_ADDRSTRLEN]; + prefix_rd2str (outbound_rd, vrf_rd_str, sizeof (vrf_rd_str)); + if ( (vrf = bgp_vrf_lookup_per_name (bgp, vrf_rd_str, 1)) == NULL) + return NULL; + } + vrf->flag &= ~BGP_VRF_RD_UNSET; + vrf->outbound_rd = *outbound_rd; + return vrf; +} + static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom) { assert (ecom->refcnt > 0); @@ -2134,6 +2179,13 @@ static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom) } void +bgp_vrf_rt_export_unset (struct bgp_vrf *vrf) +{ + if (vrf->rt_export) + ecommunity_unintern (&vrf->rt_export); +} + +void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export) { if (vrf->rt_export) @@ -2142,7 +2194,7 @@ bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export) vrf->rt_export = ecommunity_reintern (rt_export); } -static void +void bgp_vrf_rt_import_unset (struct bgp_vrf *vrf) { size_t i; @@ -2191,21 +2243,41 @@ bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import) bgp_vrf_apply_new_imports (vrf, afi); } -static void -bgp_vrf_delete_int (void *arg) +/* delete RD <> command as well as RD export/import + * and RIB table associated + */ +void +bgp_vrf_delete_rd (struct bgp_vrf *vrf) { - struct bgp_vrf *vrf = arg; char vrf_rd_str[RD_ADDRSTRLEN]; + if (!vrf) + return; + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str)); - zlog_info ("deleting vrf %s", vrf_rd_str); + zlog_info ("deleting rd %s", vrf_rd_str); bgp_vrf_clean_tables (vrf); bgp_vrf_rt_import_unset (vrf); if (vrf->rt_export) ecommunity_unintern (&vrf->rt_export); + return; +} +static void +bgp_vrf_delete_int (void *arg) +{ + struct bgp_vrf *vrf = arg; + char vrf_rd_str[RD_ADDRSTRLEN]; + + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(vrf_rd_str)); + zlog_info ("deleting vrf %s", vrf_rd_str); + + bgp_vrf_delete_rd (vrf); + + if (vrf->name) + free (vrf->name); XFREE (MTYPE_BGP_VRF, vrf); } @@ -5790,14 +5862,19 @@ bgp_config_write (struct vty *vty) char *str_p, *str2_p; for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf)) { - str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN); - vty_out(vty, " vrf rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE); + vty_out(vty, " vrf %s%s", vrf->name, VTY_NEWLINE); + /* an RD has been configured */ + if (!(vrf->flag & BGP_VRF_RD_UNSET)) + { + str_p = prefix_rd2str(&(vrf->outbound_rd), rdstr, RD_ADDRSTRLEN); + vty_out(vty, " rd %s%s", str_p == NULL?"<err>":str_p, VTY_NEWLINE); + } if(vrf->rt_import) { str2_p = ecommunity_ecom2str (vrf->rt_import, ECOMMUNITY_FORMAT_ROUTE_MAP); if(str2_p) { - vty_out(vty, " vrf rd %s import %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE); + vty_out(vty, " rt import %s%s", str2_p, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, str2_p); } } @@ -5806,10 +5883,11 @@ bgp_config_write (struct vty *vty) str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP); if(str2_p) { - vty_out(vty, " vrf rd %s export %s%s", str_p == NULL?"<err>":str_p, str2_p, VTY_NEWLINE); + vty_out(vty, " rt export %s%s", str2_p, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, str2_p); } } + vty_out (vty, " exit%s", VTY_NEWLINE); } } /* maximum-paths */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 15245ceeb8d2..c81466e85205 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -31,6 +31,8 @@ typedef u_int32_t as_t; typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */ typedef u_int16_t bgp_size_t; +struct bgp_node; + /* BGP router distinguisher value. */ #define BGP_RD_SIZE 8 @@ -208,6 +210,7 @@ struct bgp_vrf { struct bgp *bgp; + char *name; /* RD used for route advertisements */ struct prefix_rd outbound_rd; @@ -221,6 +224,10 @@ struct bgp_vrf /* Static route configuration. */ struct bgp_table *route[AFI_MAX]; + /* internal flag */ +#define BGP_VRF_RD_UNSET 1 + uint16_t flag; + }; /* BGP peer-group support. */ @@ -1033,11 +1040,16 @@ extern int peer_ttl_security_hops_set (struct peer *, int); extern int peer_ttl_security_hops_unset (struct peer *); extern void bgp_scan_finish (void); -extern struct bgp_vrf *bgp_vrf_create (struct bgp *bgp, struct prefix_rd *outbound_rd); +extern void bgp_vrf_delete_rd (struct bgp_vrf *vrf); +extern struct bgp_vrf *bgp_vrf_update_rd (struct bgp *bgp, struct bgp_vrf *vrf, struct prefix_rd *outbound_rd); extern struct bgp_vrf *bgp_vrf_lookup (struct bgp *bgp, struct prefix_rd *outbound_rd); +extern struct bgp_vrf *bgp_vrf_lookup_per_name (struct bgp *bgp, const char *name, int create); +extern struct bgp_vrf *bgp_vrf_lookup_per_rn (struct bgp *bgp, int afi, struct bgp_node *vrf_rn); extern void bgp_vrf_delete (struct bgp_vrf *vrf); extern void bgp_vrf_rt_export_set (struct bgp_vrf *vrf, struct ecommunity *rt_export); extern void bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import); extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf); +extern void bgp_vrf_rt_import_unset (struct bgp_vrf *vrf); +extern void bgp_vrf_rt_export_unset (struct bgp_vrf *vrf); #endif /* _QUAGGA_BGPD_H */ -- 2.1.4 _______________________________________________ Quagga-dev mailing list Quagga-dev@lists.quagga.net https://lists.quagga.net/mailman/listinfo/quagga-dev