[frr] [PATCH v2 0/10] BGP VRF Route Distinguisher configuration
This series of patches introduces the ability for a BGP router, to configure a route distinguisher and associate import and export route targets. This permits for a BGP update to be sent with BGP extended communities associated to the exported route targets of the RD. This permits for a BGP update to be received, and to be handled according to the imported route targets of the RD contained in BGP extended communities. This patch is rebased with latest from master branch. It also relies on RD/RT discussions. It implements partial option 6, that is to say introduction of vrf subnode under bgp router node, and subsequent rt/rd vty commands. The testing on this patch shows the ability of route processing bgp updates with associated extended communities ( according to RT export values). Route server configuration with vpnv4 has also been showed to work. The second version of this patch is adding some documentation. It also fixes an issue related to initialisation of bgp vrf context. Cheers, Philippe
This new node is to be put under router bgp subnode. On top of this, usual exit and end commands are also taking into account bgp vrf subnode. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- lib/command.c | 3 +++ lib/command.h | 1 + lib/vty.c | 1 + 3 files changed, 5 insertions(+) diff --git a/lib/command.c b/lib/command.c index ca0d0c001bad..2ba1e53f6751 100644 --- a/lib/command.c +++ b/lib/command.c @@ -750,6 +750,7 @@ node_parent ( enum node_type node ) case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_VRF_NODE: ret = BGP_NODE; break; case KEYCHAIN_KEY_NODE: @@ -1113,6 +1114,7 @@ cmd_exit (struct vty *vty) case BGP_VNC_L2_GROUP_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_VRF_NODE: vty->node = BGP_NODE; break; case LDP_IPV4_NODE: @@ -1180,6 +1182,7 @@ DEFUN (config_end, case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_VRF_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: diff --git a/lib/command.h b/lib/command.h index 1e1698fc7d12..aeda6177aa5c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -103,6 +103,7 @@ enum node_type BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */ BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */ RFP_DEFAULTS_NODE, /* RFP defaults node */ + BGP_VRF_NODE, /* BGP VRF node. */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ LDP_NODE, /* LDP protocol mode */ diff --git a/lib/vty.c b/lib/vty.c index d5ecb1db5bf1..d2c9a6af6627 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -749,6 +749,7 @@ vty_end_config (struct vty *vty) case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_VRF_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: -- 2.1.4
This commit includes changes related to introduce new subnode under bgp called vrf <>. This node permits configuring route distinguishers and route target under the subnode, by using vtysh command tool. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- vtysh/extract.pl.in | 2 ++ vtysh/vtysh.c | 42 ++++++++++++++++++++++++++++++++++++++++++ vtysh/vtysh_config.c | 6 +++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index fc5a5147f1d0..5d8b21ef135d 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -69,6 +69,8 @@ $ignore{'"exit-link-params"'} = "ignore"; $ignore{'"vnc defaults"'} = "ignore"; $ignore{'"vnc nve-group NAME"'} = "ignore"; $ignore{'"exit-vnc"'} = "ignore"; +$ignore{'"vrf WORD"'} = "ignore"; +$ignore{'"exit-bgp-vrf"'} = "ignore"; $ignore{'"key chain WORD"'} = "ignore"; $ignore{'"key (0-2147483647)"'} = "ignore"; $ignore{'"route-map WORD <deny|permit> (1-65535)"'} = "ignore"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index f67fc1f31d6b..e6b32791cd33 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -317,6 +317,10 @@ vtysh_execute_func (const char *line, int pager) || saved_node == BGP_VNC_L2_GROUP_NODE) && (tried == 1)) { vtysh_execute("exit-vnc"); + } + else if ((saved_node == BGP_VRF_NODE) && (tried == 1)) + { + vtysh_execute("exit-bgp-vrf"); } else if ((saved_node == KEYCHAIN_KEY_NODE) && (tried == 1)) { @@ -969,6 +973,13 @@ static struct cmd_node bgp_vnc_l2_group_node = "%s(config-router-vnc-l2-group)# " }; +/* VRF node. */ +static struct cmd_node bgp_vrf_node = +{ + BGP_VRF_NODE, + "%s(bgp-vrf)# " +}; + static struct cmd_node ospf_node = { OSPF_NODE, @@ -1222,6 +1233,18 @@ DEFUNSH (VTYSH_BGPD, } #endif +DEFUNSH (VTYSH_BGPD, + bgp_vrf, + bgp_vrf_cmd, + "vrf WORD", + "BGP VRF\n" + "VRF Name\n" +) +{ + vty->node = BGP_VRF_NODE; + return CMD_SUCCESS; +} + DEFUNSH (VTYSH_RIPD, key_chain, key_chain_cmd, @@ -1484,6 +1507,7 @@ vtysh_exit (struct vty *vty) case BGP_VNC_DEFAULTS_NODE: case BGP_VNC_NVE_GROUP_NODE: case BGP_VNC_L2_GROUP_NODE: + case BGP_VRF_NODE: vty->node = BGP_NODE; break; case LDP_IPV4_NODE: @@ -1560,6 +1584,17 @@ DEFUNSH (VTYSH_BGPD, return CMD_SUCCESS; } +DEFUNSH (VTYSH_BGPD, + 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; +} + DEFUNSH (VTYSH_RIPD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, @@ -3044,6 +3079,7 @@ vtysh_init_vty (void) install_node (&bgp_vnc_defaults_node, NULL); install_node (&bgp_vnc_nve_group_node, NULL); install_node (&bgp_vnc_l2_group_node, NULL); + install_node (&bgp_vrf_node, NULL); install_node (&ospf_node, NULL); install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); @@ -3082,6 +3118,7 @@ vtysh_init_vty (void) vtysh_install_default (BGP_VNC_NVE_GROUP_NODE); vtysh_install_default (BGP_VNC_L2_GROUP_NODE); #endif + vtysh_install_default (BGP_VRF_NODE); vtysh_install_default (OSPF_NODE); vtysh_install_default (RIPNG_NODE); vtysh_install_default (OSPF6_NODE); @@ -3156,6 +3193,8 @@ vtysh_init_vty (void) install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd); #endif + install_element (BGP_VRF_NODE, &vtysh_exit_bgpd_cmd); + install_element (BGP_VRF_NODE, &vtysh_quit_bgpd_cmd); install_element (ISIS_NODE, &vtysh_exit_isisd_cmd); install_element (ISIS_NODE, &vtysh_quit_isisd_cmd); install_element (KEYCHAIN_NODE, &vtysh_exit_ripd_cmd); @@ -3193,6 +3232,7 @@ vtysh_init_vty (void) 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); + install_element (BGP_VRF_NODE, &vtysh_end_all_cmd); install_element (ISIS_NODE, &vtysh_end_all_cmd); install_element (KEYCHAIN_NODE, &vtysh_end_all_cmd); install_element (KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); @@ -3246,6 +3286,7 @@ vtysh_init_vty (void) install_element (BGP_NODE, &address_family_ipv4_multicast_cmd); install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_multicast_cmd); + install_element (BGP_NODE, &bgp_vrf_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); @@ -3259,6 +3300,7 @@ vtysh_init_vty (void) install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); install_element (BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd); + install_element (BGP_VRF_NODE, &exit_bgp_vrf_cmd); install_element (CONFIG_NODE, &key_chain_cmd); install_element (CONFIG_NODE, &vtysh_route_map_cmd); install_element (CONFIG_NODE, &vtysh_line_vty_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index e60e9c091fdf..b4afd56d9298 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -187,7 +187,11 @@ vtysh_config_parse_line (const char *line) config->index == NS_NODE || config->index == VTY_NODE) config_add_line_uniq (config->line, line); - else + else if (config->index == BGP_VRF_NODE) + { + config = config_get (BGP_VRF_NODE, line); + } + else config_add_line (config->line, line); } else -- 2.1.4
Because bgp_show_type is used many times for encap and vpnv4 families, this define is moved to a single place. It will be used from this place. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- bgpd/bgp_encap.c | 16 ---------------- bgpd/bgp_mplsvpn.c | 16 ---------------- bgpd/bgp_route.c | 21 --------------------- bgpd/bgp_route.h | 21 +++++++++++++++++++++ 4 files changed, 21 insertions(+), 53 deletions(-) diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 4ea2f9cde73a..8f25de7539e3 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -332,22 +332,6 @@ show_adj_route_encap (struct vty *vty, struct peer *peer, struct prefix_rd *prd) return CMD_SUCCESS; } -enum bgp_show_type -{ - bgp_show_type_normal, - bgp_show_type_regexp, - bgp_show_type_prefix_list, - bgp_show_type_filter_list, - bgp_show_type_neighbor, - bgp_show_type_cidr_only, - bgp_show_type_prefix_longer, - bgp_show_type_community_all, - bgp_show_type_community, - bgp_show_type_community_exact, - bgp_show_type_community_list, - bgp_show_type_community_list_exact -}; - static int bgp_show_encap ( struct vty *vty, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index c64c69dfca12..3ba2f5dad9b3 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -661,22 +661,6 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u return CMD_SUCCESS; } -enum bgp_show_type -{ - bgp_show_type_normal, - bgp_show_type_regexp, - bgp_show_type_prefix_list, - bgp_show_type_filter_list, - bgp_show_type_neighbor, - bgp_show_type_cidr_only, - bgp_show_type_prefix_longer, - bgp_show_type_community_all, - bgp_show_type_community, - bgp_show_type_community_exact, - bgp_show_type_community_list, - bgp_show_type_community_list_exact -}; - static int bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int tags, u_char use_json) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cfc4ec34077f..58c88686ff51 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7217,27 +7217,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" #define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path%s" -enum bgp_show_type -{ - bgp_show_type_normal, - bgp_show_type_regexp, - bgp_show_type_prefix_list, - bgp_show_type_filter_list, - bgp_show_type_route_map, - bgp_show_type_neighbor, - bgp_show_type_cidr_only, - bgp_show_type_prefix_longer, - bgp_show_type_community_all, - bgp_show_type_community, - bgp_show_type_community_exact, - bgp_show_type_community_list, - bgp_show_type_community_list_exact, - bgp_show_type_flap_statistics, - bgp_show_type_flap_neighbor, - bgp_show_type_dampend_paths, - bgp_show_type_damp_neighbor -}; - static int bgp_show_prefix_list (struct vty *vty, const char *name, const char *prefix_list_str, afi_t afi, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 63b18aa2d8fb..1c6eac5f85d3 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -32,6 +32,27 @@ struct bgp_nexthop_cache; #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" +enum bgp_show_type +{ + bgp_show_type_normal, + bgp_show_type_regexp, + bgp_show_type_prefix_list, + bgp_show_type_filter_list, + bgp_show_type_route_map, + bgp_show_type_neighbor, + bgp_show_type_cidr_only, + bgp_show_type_prefix_longer, + bgp_show_type_community_all, + bgp_show_type_community, + bgp_show_type_community_exact, + bgp_show_type_community_list, + bgp_show_type_community_list_exact, + bgp_show_type_flap_statistics, + bgp_show_type_flap_neighbor, + bgp_show_type_dampend_paths, + bgp_show_type_damp_neighbor +}; + /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. -- 2.1.4
This commit introduces the BGP VRF configuration, and BGP VRF RIB table. It includes the ability for a BGP to configure its own route distinguisher ( aka VRF). A new subnode under router bgp command has been created: vrf <>. New vty commands introduced: 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 <> It brings some improvements. - for a BGP speaker when emitting BGP updates, the exported route targets will be mapped to BGP extended communities associated with the BGP update for the defined Route distinguisher. This commit does not enhance the support for emitting those BGP extended communities, but provides the mecanism. - for a BGP speaker when receiving BGP updaets. Its import route target will be looked up, in order to match NLRI route distinguisher. Then, if matching, the entry would be exported to a RIB per VRF table. As mentioned before, the commit also introduces a BGP VRF RIB table per Route distinguisher configured. This table aims at receiving BGP NLRI entries, with matching import and export route targets. This commit does not take into account the fullfill of this table, but creates it. Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- bgpd/Makefile.am | 4 +- bgpd/bgp_memory.c | 3 + bgpd/bgp_memory.h | 2 + bgpd/bgp_route.c | 55 +++- bgpd/bgp_route.h | 14 ++ bgpd/bgp_table.h | 10 + bgpd/bgp_vrf.c | 734 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_vrf.h | 84 +++++++ bgpd/bgp_vty.c | 1 + bgpd/bgpd.c | 6 + bgpd/bgpd.h | 7 + 11 files changed, 914 insertions(+), 6 deletions(-) create mode 100644 bgpd/bgp_vrf.c create mode 100644 bgpd/bgp_vrf.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 69c0504af451..50f364a6358e 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -78,7 +78,7 @@ libbgp_a_SOURCES = \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ - bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) + bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_vrf.c noinst_HEADERS = \ bgp_memory.h \ @@ -88,7 +88,7 @@ noinst_HEADERS = \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) + $(BGP_VNC_RFAPI_HD) bgp_vrf.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libzebra.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 72c0311c1710..a3cb031631cc 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -111,3 +111,6 @@ DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV") DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options") DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value") + +DEFINE_MTYPE(BGPD, BGP_VRF, "BGP VRF Data Structures") +DEFINE_MTYPE(BGPD, BGP_RT_SUB, "BGP Route Target Data Structures") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index a4ce8b891b22..f4ed2b42dba4 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -108,4 +108,6 @@ DECLARE_MTYPE(ENCAP_TLV) DECLARE_MTYPE(BGP_TEA_OPTIONS) DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE) +DECLARE_MTYPE(BGP_VRF) +DECLARE_MTYPE(BGP_RT_SUB) #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 58c88686ff51..389f2de6f325 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -59,6 +59,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_vrf.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -70,6 +71,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; +static void +bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct prefix_rd *prd, u_char *tag); +static void +bgp_static_free (struct bgp_static *bgp_static); + struct bgp_node * bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd) @@ -86,7 +93,12 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix prn = bgp_node_get (table, (struct prefix *) prd); if (prn->info == NULL) - prn->info = bgp_table_init (afi, safi); + { + struct bgp_table *newtab = bgp_table_init (afi, safi); + if (prd) + newtab->prd = *prd; + prn->info = newtab; + } else bgp_unlock_node (prn); table = prn->info; @@ -6568,6 +6580,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, attr = binfo->attr; + if (safi == SAFI_MPLS_LABELED_VPN) + safi = SAFI_MPLS_VPN; + if (attr) { /* Line1 display AS-path, Aggregator */ @@ -7244,7 +7259,7 @@ static int bgp_show_community (struct vty *vty, const char *view_name, int argc, struct cmd_token **argv, int exact, afi_t afi, safi_t safi); -static int +int bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, enum bgp_show_type type, void *output_arg, u_char use_json) { @@ -7658,7 +7673,7 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, } /* Display specified route of BGP table. */ -static int +int bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, @@ -10530,7 +10545,6 @@ bgp_route_init (void) install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd); - install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); @@ -10640,3 +10654,36 @@ bgp_route_finish (void) bgp_distance_table[afi][safi] = NULL; } } + +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; + struct bgp_node *rn; + + for (rn = bgp_table_top (vrf->rib[afi]); rn; rn = bgp_route_next (rn)) + for (ri = rn->info; ri; ri = ri_next) + { + ri_next = ri->next; + bgp_info_reap (rn, ri); + } + bgp_table_finish (&vrf->rib[afi]); + + for (rn = bgp_table_top (vrf->route[afi]); rn; rn = bgp_route_next (rn)) + if (rn->info) + { + struct bgp_static *bs = rn->info; + bgp_static_withdraw_safi (vrf->bgp, &rn->p, afi, SAFI_MPLS_VPN, + &vrf->outbound_rd, NULL); + bgp_static_free (bs); + rn->info = NULL; + bgp_unlock_node (rn); + } + bgp_table_finish (&vrf->route[afi]); + } +} diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 1c6eac5f85d3..ba6dc86a8e2f 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgp_table.h" struct bgp_nexthop_cache; +struct bgp_vrf; #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\ "h history, * valid, > best, = multipath,%s"\ @@ -94,6 +95,7 @@ struct bgp_info_extra } vnc; #endif + struct prefix_rd vrf_rd; }; struct bgp_info @@ -366,4 +368,16 @@ extern void bgp_info_restore (struct bgp_node *, struct bgp_info *); extern int bgp_info_cmp_compatible (struct bgp *, struct bgp_info *, struct bgp_info *, afi_t, safi_t ); +extern int +bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, + struct bgp_table *rib, const char *ip_str, + afi_t afi, safi_t safi, struct prefix_rd *prd, + int prefix_check, enum bgp_path_type pathtype, + u_char use_json); +extern void bgp_vrf_clean_tables (struct bgp_vrf *vrf); + +extern int +bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, + enum bgp_show_type type, void *output_arg, u_char use_json); + #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 2f839c4af7dd..9f78838c40ae 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -23,8 +23,16 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "table.h" +typedef enum +{ + BGP_TABLE_MAIN, + BGP_TABLE_VRF, +} bgp_table_t; + struct bgp_table { + bgp_table_t type; + /* afi/safi of this table */ afi_t afi; safi_t safi; @@ -36,6 +44,8 @@ struct bgp_table struct route_table *route_table; uint64_t version; + + struct prefix_rd prd; }; struct bgp_node diff --git a/bgpd/bgp_vrf.c b/bgpd/bgp_vrf.c new file mode 100644 index 000000000000..3923fe365892 --- /dev/null +++ b/bgpd/bgp_vrf.c @@ -0,0 +1,734 @@ +/* BGP-4, BGP-4+ daemon program + Copyright (C) 2016, 6WIND + +This file is part of GNU Quagga. + +GNU Quagga is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Quagga is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Quagga; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include <zebra.h> + +#include "prefix.h" +#include "linklist.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_vty.h" +#include "bgpd/bgp_vrf.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_attr.h" + +static int +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi, + enum bgp_show_type type, void *output_arg, u_char use_json); + +static int +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str, + afi_t afi, int prefix_check,u_char use_json); + +/* for vty access to bgp vrf node */ +DEFINE_QOBJ_TYPE(bgp_vrf) + +/* for vty config, BGP VRF node. */ +static struct cmd_node bgp_vrf_node = +{ + BGP_VRF_NODE, + "%s(bgp-vrf)# ", + 1 +}; + +static struct ecommunity * ecommunity_reintern (struct ecommunity *ecom) +{ + assert (ecom->refcnt > 0); + ecom->refcnt++; + return ecom; +} + +/* route target internals */ +static unsigned int bgp_rt_hash_key (void *arg) +{ + const struct bgp_rt_sub *rt_sub = arg; + uint32_t *rtval = (uint32_t *)(char *)&rt_sub->rt; + return rtval[0] ^ rtval[1]; +} + +static int bgp_rt_hash_cmp (const void *a, const void *b) +{ + const struct bgp_rt_sub *aa = a, *bb = b; + return !memcmp(&aa->rt, &bb->rt, sizeof(aa->rt)); +} + +static void * +bgp_rt_hash_alloc (void *dummy) +{ + struct bgp_rt_sub *ddummy = dummy, *rt_sub; + rt_sub = XMALLOC (MTYPE_BGP_RT_SUB, sizeof (*rt_sub)); + rt_sub->rt = ddummy->rt; + rt_sub->vrfs = list_new(); + return rt_sub; +} + +static void +bgp_rt_hash_dealloc (struct bgp_rt_sub *rt_sub) +{ + list_delete (rt_sub->vrfs); + XFREE (MTYPE_BGP_RT_SUB, rt_sub); +} + +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) + ecommunity_unintern (&vrf->rt_export); + + vrf->rt_export = ecommunity_reintern (rt_export); +} + +void +bgp_vrf_rt_import_unset (struct bgp_vrf *vrf) +{ + size_t i; + + if (!vrf->rt_import) + return; + + for (i = 0; i < (size_t)vrf->rt_import->size; i++) + { + struct bgp_rt_sub dummy, *rt_sub; + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8); + + rt_sub = hash_lookup (vrf->bgp->rt_subscribers, &dummy); + assert(rt_sub); + listnode_delete (rt_sub->vrfs, vrf); + if (list_isempty (rt_sub->vrfs)) + { + hash_release (vrf->bgp->rt_subscribers, rt_sub); + bgp_rt_hash_dealloc (rt_sub); + } + } + + ecommunity_unintern (&vrf->rt_import); +} + +void +bgp_vrf_rt_import_set (struct bgp_vrf *vrf, struct ecommunity *rt_import) +{ + size_t i; + afi_t afi; + + bgp_vrf_rt_import_unset (vrf); + + vrf->rt_import = ecommunity_reintern (rt_import); + + for (i = 0; i < (size_t)vrf->rt_import->size; i++) + { + struct bgp_rt_sub dummy, *rt_sub; + memcpy (&dummy.rt, vrf->rt_import->val + 8 * i, 8); + + rt_sub = hash_get (vrf->bgp->rt_subscribers, &dummy, bgp_rt_hash_alloc); + listnode_add (rt_sub->vrfs, vrf); + } + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + bgp_vrf_apply_new_imports (vrf, afi); +} + +/* bgp vrf internals */ +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; +} + +/* delete RD <> command as well as RD export/import + * and RIB table associated + */ +void +bgp_vrf_delete_rd (struct bgp_vrf *vrf) +{ + char vrf_rd_str[RD_ADDRSTRLEN]; + + if (!vrf) + return; + + prefix_rd2str(&vrf->outbound_rd, vrf_rd_str, sizeof(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); + QOBJ_UNREG (vrf); + XFREE (MTYPE_BGP_VRF, vrf); +} + +void +bgp_vrf_context_delete (struct bgp_vrf *vrf) +{ + listnode_delete (vrf->bgp->vrfs, vrf); + bgp_vrf_delete_int(vrf); +} + +void +bgp_vrf_apply_new_imports (struct bgp_vrf *vrf, afi_t afi) +{ + struct bgp_node *rd_rn, *rn; + struct bgp_info *sel; + struct bgp_table *table; + struct ecommunity *ecom; + size_t i, j; + bool found; + + if (!vrf->rt_import || vrf->rt_import->size == 0) + return; + + for (rd_rn = bgp_table_top (vrf->bgp->rib[afi][SAFI_MPLS_VPN]); rd_rn; + rd_rn = bgp_route_next (rd_rn)) + if (rd_rn->info != NULL) + { + table = rd_rn->info; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + { + for (sel = rn->info; sel; sel = sel->next) + if (CHECK_FLAG (sel->flags, BGP_INFO_SELECTED)) + break; + if (!sel || !sel->attr || !sel->attr->extra) + continue; + ecom = sel->attr->extra->ecommunity; + if (!ecom) + continue; + + found = false; + for (i = 0; i < (size_t)ecom->size && !found; i++) + for (j = 0; j < (size_t)vrf->rt_import->size && !found; j++) + if (!memcmp(ecom->val + i * 8, vrf->rt_import->val + j * 8, 8)) + found = true; + if (!found) + continue; + } + } +} + +struct bgp_vrf * +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 (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; + QOBJ_REG (vrf, bgp_vrf); + vrf->bgp = bgp; + vrf->name = strdup (name); + vrf->flag |= BGP_VRF_RD_UNSET; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + { + vrf->route[afi] = bgp_table_init (afi, SAFI_UNICAST); + vrf->route[afi]->type = BGP_TABLE_VRF; + vrf->rib[afi] = bgp_table_init (afi, SAFI_UNICAST); + vrf->rib[afi]->type = BGP_TABLE_VRF; + } + + listnode_add (bgp->vrfs, vrf); + return vrf; +} + +/* VTY configuration and exploitation */ + +DEFUN (bgp_vrf, + bgp_vrf_cmd, + "vrf WORD", + "BGP VRF\n" + "VRF Name\n" +) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct bgp_vrf *vrf; + if ( (vrf = bgp_vrf_lookup_per_name (bgp, (const char *)argv[1]->arg, 1)) == NULL) + return CMD_ERR_NO_MATCH; + VTY_PUSH_CONTEXT_SUB (BGP_VRF_NODE, vrf); + return CMD_SUCCESS; +} + +DEFUN (no_bgp_vrf, + no_bgp_vrf_cmd, + "no vrf WORD", + NO_STR + "BGP VRF\n" + "VRF Name\n" +) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct bgp_vrf *vrf; + + vrf = bgp_vrf_lookup_per_name (bgp, argv[2]->arg, 0); + if (! vrf) + { + vty_out (vty, "%% No VRF with name '%s'%s", argv[2]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + bgp_vrf_context_delete (vrf); + return CMD_SUCCESS; +} + +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_rd, + bgp_vrf_rd_cmd, + "rd WORD", + "Route Distinguisher\n" + "Route Distinguisher Name\n" +) +{ + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct prefix_rd prd; + + if (! str2prefix_rd (argv[1]->arg, &prd)) + { + vty_out (vty, "%% Invalid RD '%s'%s", argv[1]->arg, VTY_NEWLINE); + 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" +) +{ + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct ecommunity *ecom = NULL; + int idx_line = 2; + char *rts; + + + /* forge export list */ + rts = argv_concat(argv, argc, idx_line); + + /* convert list of ecoms string into ecom struct */ + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 0); + if (! ecom) + { + vty_out (vty, "%% Invalid RT '%s'%s", rts, VTY_NEWLINE); + return CMD_WARNING; + } + if (rts) + XFREE (MTYPE_TMP, rts); + + ecom = ecommunity_intern (ecom); + bgp_vrf_rt_export_set (vrf, ecom); + ecommunity_unintern (&ecom); + return CMD_SUCCESS; +} + +DEFUN (bgp_vrf_rt_import, + bgp_vrf_rt_import_cmd, + "rt import LINE...", + "Route Target\n" + "Import RT values\n" + "Import RT values\n" +) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + struct ecommunity *ecom = NULL; + char *rts; + int idx_line = 2; + + /* forge import list */ + rts = argv_concat(argv, argc, idx_line); + + /* convert list of ecoms string into ecom struct */ + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 0); + if (! ecom) + { + vty_out (vty, "%% Invalid RT '%s'%s", rts, VTY_NEWLINE); + return CMD_WARNING; + } + if (rts) + XFREE (MTYPE_TMP, rts); + + ecom = ecommunity_intern (ecom); + bgp_vrf_rt_import_set (vrf, ecom); + ecommunity_unintern (&ecom); + return CMD_SUCCESS; +} + +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" +) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + struct ecommunity *ecom = NULL, *ecom1; + char *rts; + int idx_line = 2; + + /* forge export/import list */ + rts = argv_concat(argv, argc, idx_line); + + /* convert list of ecoms string into ecom struct */ + ecom = ecommunity_str2com (rts, ECOMMUNITY_ROUTE_TARGET, 1); + if (! ecom) + { + vty_out (vty, "%% Invalid RT '%s'%s", rts, VTY_NEWLINE); + return CMD_WARNING; + } + if (rts) + XFREE (MTYPE_TMP, rts); + + 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" +) +{ + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + + 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" +) +{ + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + + 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" +) +{ + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + + 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" +) +{ + VTY_DECLVAR_CONTEXT_SUB (bgp_vrf, vrf); + + bgp_vrf_delete_rd (vrf); + return CMD_SUCCESS; +} + +static int +bgp_show_vrf (struct vty *vty, const char *vrf_name, afi_t afi, + enum bgp_show_type type, void *output_arg, u_char use_json) +{ + struct bgp *bgp = bgp_get_default(); + struct bgp_vrf *vrf; + + if (! bgp) + { + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + vrf = bgp_vrf_lookup_per_name (bgp, vrf_name, 0); + if (! vrf) + { + vty_out (vty, "%% No VRF with name '%s'%s", vrf_name, VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_table (vty, bgp, vrf->rib[afi], type, output_arg, use_json); +} + +static int +bgp_show_vrf_route (struct vty *vty, const char *vrf_name, const char *ip_str, + afi_t afi, int prefix_check,u_char use_json) +{ + struct bgp *bgp = bgp_get_default(); + struct bgp_vrf *vrf; + + if (! bgp) + { + vty_out (vty, "%% No default BGP instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + vrf = bgp_vrf_lookup_per_name (bgp, vrf_name, 0); + if (! vrf) + { + vty_out (vty, "%% No VRF with name '%s'%s", vrf_name, VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_route_in_table (vty, bgp, vrf->rib[afi], ip_str, + afi, SAFI_MPLS_LABELED_VPN, NULL, + prefix_check, BGP_PATH_ALL, use_json); +} + +DEFUN (show_ip_bgp_vrf, + show_ip_bgp_vrf_cmd, + "show ip bgp bgpvrf WORD [json]", + SHOW_STR + IP_STR + BGP_STR + "BGP VRF" + "BGP VRF Name" + JSON_STR) +{ + return bgp_show_vrf (vty, argv[4]->arg, AFI_IP, bgp_show_type_normal, NULL, use_json(argc, argv)); +} + +DEFUN (show_ipv6_bgp_vrf, + show_ipv6_bgp_vrf_cmd, + "show ipv6 bgp bgpvrf WORD [json]", + SHOW_STR + "IPv6" + BGP_STR + "BGP VRF" + "BGP VRF Name" + JSON_STR) +{ + return bgp_show_vrf (vty, argv[4]->arg, AFI_IP6, bgp_show_type_normal, NULL, use_json(argc, argv)); +} + +DEFUN (show_ip_bgp_vrf_route, + show_ip_bgp_vrf_route_cmd, + "show ip bgp bgpvrf WORD A.B.C.D [json]", + SHOW_STR + IP_STR + BGP_STR + "VRF\n" + "BGP VRF Name\n" + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" + JSON_STR) +{ + return bgp_show_vrf_route (vty, argv[4]->arg, argv[5]->arg, AFI_IP, 0, use_json (argc,argv)); +} + +DEFUN (show_ipv6_bgp_vrf_route, + show_ipv6_bgp_vrf_route_cmd, + "show ipv6 bgp bgpvrf WORD X:X::X:X [json]", + SHOW_STR + IP_STR + BGP_STR + "VRF\n" + "BGP VRF Name\n" + "IPv6 prefix <network>/<length>\n" + "JavaScript Object Notation\n") +{ + return bgp_show_vrf_route (vty, argv[4]->arg, argv[5]->arg, AFI_IP6, 0, use_json (argc,argv)); +} + +/* BGP VRF init/delete/ show running */ +void +bgp_bgpvrf_init (struct bgp *bgp) +{ + bgp->vrfs = list_new(); + bgp->vrfs->del = bgp_vrf_delete_int; + bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp); + + install_node (&bgp_vrf_node, NULL); + install_default (BGP_VRF_NODE); + + install_element (BGP_NODE, &bgp_vrf_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); + + install_element (VIEW_NODE, &show_ip_bgp_vrf_cmd); + install_element (VIEW_NODE, &show_ip_bgp_vrf_route_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_vrf_cmd); + install_element (VIEW_NODE, &show_ipv6_bgp_vrf_route_cmd); +} + +void +bgp_bgpvrf_delete (struct bgp *bgp) +{ + if(bgp->vrfs) + list_delete (bgp->vrfs); + bgp->vrfs = NULL; + if(bgp->rt_subscribers) + { + hash_clean (bgp->rt_subscribers, NULL); + hash_free (bgp->rt_subscribers); + bgp->rt_subscribers = NULL; + } +} + +void bgp_config_write_bgpvrf (struct vty *vty, struct bgp *bgp) +{ + struct bgp_vrf *vrf; + char rdstr[RD_ADDRSTRLEN]; + char *str_p, *str2_p; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(bgp->vrfs, node, vrf)) + { + 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, " rt import %s%s", str2_p, VTY_NEWLINE); + XFREE (MTYPE_ECOMMUNITY_STR, str2_p); + } + } + if(vrf->rt_export) + { + str2_p = ecommunity_ecom2str (vrf->rt_export, ECOMMUNITY_FORMAT_ROUTE_MAP); + if(str2_p) + { + vty_out(vty, " rt export %s%s", str2_p, VTY_NEWLINE); + XFREE (MTYPE_ECOMMUNITY_STR, str2_p); + } + } + vty_out (vty, " exit%s", VTY_NEWLINE); + } +} diff --git a/bgpd/bgp_vrf.h b/bgpd/bgp_vrf.h new file mode 100644 index 000000000000..f8dd4489b0e0 --- /dev/null +++ b/bgpd/bgp_vrf.h @@ -0,0 +1,84 @@ +/* BGP VRF definition header + Copyright (C) 2016, 6WIND + +This file is part of GNU Quagga. + +GNU Quagga is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Quagga is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Quagga; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _QUAGGA_BGP_VRF_H +#define _QUAGGA_BGP_VRF_H + + +#include "qobj.h" +#include "linklist.h" +#include "prefix.h" + +#include "bgpd.h" +#include "bgp_table.h" +#include "bgp_ecommunity.h" + +struct bgp_rt_sub +{ + struct ecommunity_val rt; + + struct list *vrfs; +}; + +struct bgp_vrf +{ + struct bgp *bgp; + + char *name; + + /* RD used for route advertisements */ + struct prefix_rd outbound_rd; + + /* import and export lists */ + struct ecommunity *rt_import; + struct ecommunity *rt_export; + + /* BGP routing information base. */ + struct bgp_table *rib[AFI_MAX]; + + /* Static route configuration. */ + struct bgp_table *route[AFI_MAX]; + + /* internal flag */ +#define BGP_VRF_RD_UNSET 1 + uint16_t flag; + + QOBJ_FIELDS +}; +DECLARE_QOBJ_TYPE(bgp_vrf) + +extern void bgp_bgpvrf_init (struct bgp *bgp); +extern void bgp_bgpvrf_delete (struct bgp *bgp); +extern void bgp_config_write_bgpvrf (struct vty *vty, struct bgp *bgp); + +extern void bgp_vrf_context_delete (struct bgp_vrf *vrf); +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_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_apply_new_imports (struct bgp_vrf *vrf, afi_t afi); +extern void bgp_vrf_rt_import_unset (struct bgp_vrf *vrf); +extern void bgp_vrf_rt_export_unset (struct bgp_vrf *vrf); + +#endif /* _QUAGGA_BGP_VRF */ + diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1c2cc037f9d8..c67e2993b764 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -56,6 +56,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_packet.h" #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" +#include "bgpd/bgp_vrf.h" static struct peer_group * listen_range_exists (struct bgp *bgp, struct prefix *range, int exact); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 30f6e0d859a5..a1b9d204ace1 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -34,6 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "log.h" #include "plist.h" #include "linklist.h" +#include "hash.h" #include "workqueue.h" #include "queue.h" #include "zclient.h" @@ -77,6 +78,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_vrf.h" DEFINE_QOBJ_TYPE(bgp_master) DEFINE_QOBJ_TYPE(bgp) @@ -2923,6 +2925,7 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type) bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX; bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME; + bgp_bgpvrf_init (bgp); QOBJ_REG (bgp, bgp); @@ -3168,6 +3171,7 @@ bgp_delete (struct bgp *bgp) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } + bgp_bgpvrf_delete (bgp); /* Delete static routes (networks). */ bgp_static_delete (bgp); @@ -7436,6 +7440,8 @@ bgp_config_write (struct vty *vty) /* listen range and limit for dynamic BGP neighbors */ bgp_config_write_listen (vty, bgp); + /* bgp vrf configuration */ + bgp_config_write_bgpvrf (vty, bgp); /* No auto-summary */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 86fa207b6b7f..38c4471b5c83 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -62,6 +62,7 @@ typedef u_int16_t bgp_size_t; __typeof__ (b) _b = (b); \ _a > _b ? _a : _b; }) + enum bgp_af_index { BGP_AF_START, @@ -361,8 +362,14 @@ struct bgp struct rfapi *rfapi; #endif + /* VRFs */ + struct list *vrfs; + + struct hash *rt_subscribers; + QOBJ_FIELDS }; + DECLARE_QOBJ_TYPE(bgp) #define BGP_ROUTE_ADV_HOLD(bgp) (bgp->main_peers_update_hold) -- 2.1.4
As bgpd has its own processing queue for calculating route entries and populating globalRIB table, a new queue is defined so as to do the same for VRF RIB tables. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- bgpd/bgp_fsm.c | 2 ++ bgpd/bgp_route.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- bgpd/bgpd.c | 5 +++++ bgpd/bgpd.h | 1 + 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 60a647533090..00168842b9b9 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -617,6 +617,7 @@ bgp_update_delay_end (struct bgp *bgp) /* Resume the queue processing. This should trigger the event that would take care of processing any work that was queued during the read-only mode. */ work_queue_unplug(bm->process_main_queue); + work_queue_unplug(bm->process_vrf_queue); } /** @@ -873,6 +874,7 @@ bgp_update_delay_begin (struct bgp *bgp) /* Stop the processing of queued work. Enqueue shall continue */ work_queue_plug(bm->process_main_queue); + work_queue_plug(bm->process_vrf_queue); for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) peer->update_delay_over = 0; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 389f2de6f325..76ca587d95fe 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2022,6 +2022,18 @@ bgp_process_main (struct work_queue *wq, void *data) return WQ_SUCCESS; } +/* processing done for BGP VRF tables */ +static wq_item_status +bgp_process_vrf_main (struct work_queue *wq, void *data) +{ + struct bgp_process_queue *pq = data; + struct bgp_node *rn = pq->rn; + + if (rn) + UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); + return WQ_SUCCESS; +} + static void bgp_processq_del (struct work_queue *wq, void *data) { @@ -2052,6 +2064,17 @@ bgp_process_queue_init (void) exit (1); } } + if (!bm->process_vrf_queue) + { + bm->process_vrf_queue + = work_queue_new (bm->master, "process_vrf_queue"); + + if ( !bm->process_vrf_queue) + { + zlog_err ("%s: Failed to allocate work queue", __func__); + exit (1); + } + } bm->process_main_queue->spec.workfunc = &bgp_process_main; bm->process_main_queue->spec.del_item_data = &bgp_processq_del; @@ -2059,6 +2082,14 @@ bgp_process_queue_init (void) bm->process_main_queue->spec.hold = 50; /* Use a higher yield value of 50ms for main queue processing */ bm->process_main_queue->spec.yield = 50 * 1000L; + + bm->process_vrf_queue->spec.workfunc = &bgp_process_vrf_main; + bm->process_vrf_queue->spec.del_item_data = &bgp_processq_del; + bm->process_vrf_queue->spec.max_retries = 0; + bm->process_vrf_queue->spec.hold = 50; + /* Use a higher yield value of 50ms for main queue processing */ + bm->process_vrf_queue->spec.yield = 50 * 1000L; + } void @@ -2070,7 +2101,8 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) if (CHECK_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED)) return; - if (bm->process_main_queue == NULL) + if ((bm->process_main_queue == NULL) || + (bm->process_vrf_queue == NULL)) bgp_process_queue_init (); pqnode = XCALLOC (MTYPE_BGP_PROCESS_QUEUE, @@ -2085,7 +2117,15 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) bgp_lock (bgp); pqnode->afi = afi; pqnode->safi = safi; - work_queue_add (bm->process_main_queue, pqnode); + switch (bgp_node_table (rn)->type) + { + case BGP_TABLE_MAIN: + work_queue_add (bm->process_main_queue, pqnode); + break; + case BGP_TABLE_VRF: + work_queue_add (bm->process_vrf_queue, pqnode); + break; + } SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a1b9d204ace1..f055f6853084 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7629,6 +7629,11 @@ bgp_terminate (void) work_queue_free (bm->process_main_queue); bm->process_main_queue = NULL; } + if (bm->process_vrf_queue) + { + work_queue_free (bm->process_vrf_queue); + bm->process_vrf_queue = NULL; + } if (bm->t_rmap_update) BGP_TIMER_OFF(bm->t_rmap_update); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 38c4471b5c83..00d96b51603f 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -95,6 +95,7 @@ struct bgp_master /* work queues */ struct work_queue *process_main_queue; + struct work_queue *process_vrf_queue; /* Listening sockets */ struct list *listen_sockets; -- 2.1.4
If the user preconfigures a vrf with import and export rules, before creating a new network on vpnv4 address, then BGP update emitted will contain the exported rts mentioned by the vrf export rule. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- bgpd/bgp_route.c | 11 +++++++++++ bgpd/bgp_route.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 76ca587d95fe..25b30ef88d3f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3921,6 +3921,11 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + if (bgp_static->ecomm) + { + bgp_attr_extra_get (&attr)->ecommunity = ecommunity_dup (bgp_static->ecomm); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); + } /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -4340,6 +4345,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, struct bgp_node *rn; struct bgp_table *table; struct bgp_static *bgp_static; + struct bgp_vrf *vrf; u_char tag[3]; ret = str2prefix (ip_str, &p); @@ -4388,6 +4394,11 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; memcpy(bgp_static->tag, tag, 3); + vrf = bgp_vrf_lookup(bgp, &prd); + if (vrf) + { + bgp_static->ecomm = vrf->rt_export; + } bgp_static->prd = prd; if (rmap_str) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index ba6dc86a8e2f..f04a88749da6 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -198,6 +198,8 @@ struct bgp_static /* Route Distinguisher */ struct prefix_rd prd; + struct ecommunity *ecomm; + /* MPLS label. */ u_char tag[3]; }; -- 2.1.4
This commit is a complement of fix from previous commit: bgpd: VRF vty configuration, RIB table creation. This permits enhancing route server for VPNv4 address-families. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- bgpd/bgp_route.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 25b30ef88d3f..759af7b36006 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -97,6 +97,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix struct bgp_table *newtab = bgp_table_init (afi, safi); if (prd) newtab->prd = *prd; + newtab->type = table->type; + newtab->owner = table->owner; prn->info = newtab; } else -- 2.1.4
This commit fixes VRF vty configuration, RIB table creation,where initialisation of vty and bgp vrf was done at once. Side effect of this was that the make check procedure could not be performed at all. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- bgpd/bgp_vrf.c | 4 ++++ bgpd/bgp_vrf.h | 1 + bgpd/bgp_vty.c | 3 +++ 3 files changed, 8 insertions(+) diff --git a/bgpd/bgp_vrf.c b/bgpd/bgp_vrf.c index 3923fe365892..221eeff7e1b7 100644 --- a/bgpd/bgp_vrf.c +++ b/bgpd/bgp_vrf.c @@ -660,6 +660,10 @@ bgp_bgpvrf_init (struct bgp *bgp) bgp->vrfs->del = bgp_vrf_delete_int; bgp->rt_subscribers = hash_create(bgp_rt_hash_key, bgp_rt_hash_cmp); +} + +void bgp_bgpvrf_vty (void) +{ install_node (&bgp_vrf_node, NULL); install_default (BGP_VRF_NODE); diff --git a/bgpd/bgp_vrf.h b/bgpd/bgp_vrf.h index f8dd4489b0e0..81d491331d36 100644 --- a/bgpd/bgp_vrf.h +++ b/bgpd/bgp_vrf.h @@ -64,6 +64,7 @@ struct bgp_vrf }; DECLARE_QOBJ_TYPE(bgp_vrf) +extern void bgp_bgpvrf_vty (void); extern void bgp_bgpvrf_init (struct bgp *bgp); extern void bgp_bgpvrf_delete (struct bgp *bgp); extern void bgp_config_write_bgpvrf (struct vty *vty, struct bgp *bgp); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c67e2993b764..fd81f860876c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10695,6 +10695,9 @@ bgp_vty_init (void) /* Community-list. */ community_list_vty (); + + /* bgp vrf */ + bgp_bgpvrf_vty (); } #include "memory.h" -- 2.1.4
Some basic information is given on the ability of BGP to handle VPNv4 entries, along with VRF. For processing , and for importing. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> --- doc/bgpd.texi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index 54bed102f3f7..6c645307fa74 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -32,6 +32,8 @@ BGP-4. * Capability Negotiation:: * Route Reflector:: * Route Server:: +* VPNv4 VRF Route Processing:: +* VPNv4 VRF Import Processing:: * How to set up a 6-Bone connection:: * Dump BGP packets and table:: * BGP Configuration Examples:: @@ -1551,6 +1553,28 @@ for managing different routing policies for each BGP speaker. We call the routing tables as different @code{view}s. @command{bgpd} can work as normal BGP router or Route Server or both at the same time. +@node VPNv4 VRF Route Processing +@section VPNv4 VRF Route Processing + +It is possible for BGP speaker to exchange overlay network tunneling +information via BGP ENCAP or VPNv4 MP-BGP extension. This information +is often tightly related to namespacing information. For that, it is +possible to send this information within a BGP VRF instance. MP-BGP +extension plans for usage of route distinguisher in message, so that +it is possible to populate remote VPNv4 entries in global RIB table, +based on route distinguisher entries + +@node VPNv4 VRF Import Processing +@section VPNv4 VRF Import Processing + +It is also possible for BGP speakers that communicate VPNv4 entries +to export the entries for a set of route target. The route targets are +associated with the BGP update message, in BGP extended communities, +and is associated with the VPNv4 entry. The incoming route target set +will match a VRF in remote BGP speaker, and the entry will then be +populated per BGP VRF RIB table. + + @menu * Multiple instance:: * BGP instance and view:: -- 2.1.4
From: David Lamparter <equinox@opensourcerouting.org> This commit is ensuring that VRF context is well initialised before performing BGP testing. Signed-off-by: David Lamparter <equinox@opensourcerouting.org> --- tests/bgp_mpath_test.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/bgp_mpath_test.c b/tests/bgp_mpath_test.c index 723f2977d585..38b758f53d10 100644 --- a/tests/bgp_mpath_test.c +++ b/tests/bgp_mpath_test.c @@ -28,6 +28,7 @@ #include "stream.h" #include "privs.h" #include "linklist.h" +#include "hash.h" #include "memory.h" #include "zclient.h" #include "queue.h" @@ -86,6 +87,17 @@ struct zebra_privs_t bgpd_privs = static int tty = 0; +static unsigned int +hash_make_dummy (void *arg) +{ + return 0; +} +static int +hash_cmp_dummy (const void *a, const void *b) +{ + return 0; +} + /* Create fake bgp instance */ static struct bgp * bgp_create_fake (as_t *as, const char *name) @@ -107,6 +119,9 @@ bgp_create_fake (as_t *as, const char *name) bgp->group = list_new (); //bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; + bgp->vrfs = list_new (); + bgp->rt_subscribers = hash_create (hash_make_dummy, hash_cmp_dummy); + for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { -- 2.1.4
participants (1)
-
Philippe Guibert