From c200f5e1e44b5f929e72cc628d0aaaf644f6a26a Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Jun 2018 13:54:47 +0200 Subject: [PATCH 01/13] lib: offer an API to get and set default vrf name The get API is used each time the VRF_DEFAULT_NAME macro is used. The set API is not yet used. Signed-off-by: Philippe Guibert --- lib/vrf.c | 35 +++++++++++++++++++++++++++++++---- lib/vrf.h | 6 ++++-- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index ecd09a6b91..8778d93f05 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -39,6 +39,7 @@ /* default VRF ID value used when VRF backend is not NETNS */ #define VRF_DEFAULT_INTERNAL 0 +#define VRF_DEFAULT_NAME_INTERNAL "Default-IP-Routing-Table" DEFINE_MTYPE_STATIC(LIB, VRF, "VRF") DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map") @@ -56,6 +57,7 @@ struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name); static int vrf_backend; static struct zebra_privs_t *vrf_daemon_privs; +static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL; /* * Turn on/off debug code @@ -876,12 +878,37 @@ void vrf_cmd_init(int (*writefunc)(struct vty *vty), } } +void vrf_set_default_name(const char *default_name) +{ + struct vrf *def_vrf; + + def_vrf = vrf_lookup_by_id(VRF_DEFAULT); + assert(default_name); + vrf_with_default_name = vrf_lookup_by_name(default_name); + if (vrf_with_default_name && vrf_with_default_name != def_vrf) { + /* vrf name already used by an other VRF */ + zlog_debug("VRF: %s, avoid changing name to %s, same name exists (%u)", + vrf_with_default_name->name, default_name, + vrf_with_default_name->vrf_id); + return; + } + snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name); + if (def_vrf) { + RB_REMOVE(vrf_name_head, &vrfs_by_name, def_vrf); + strlcpy(def_vrf->data.l.netns_name, + vrf_default_name, NS_NAMSIZ); + strlcpy(def_vrf->name, vrf_default_name, sizeof(def_vrf->name)); + RB_INSERT(vrf_name_head, &vrfs_by_name, def_vrf); + } +} + +const char *vrf_get_default_name(void) +{ + return vrf_default_name; +} + vrf_id_t vrf_get_default_id(void) { - struct vrf *vrf = vrf_lookup_by_name(VRF_DEFAULT_NAME); - - if (vrf) - return vrf->vrf_id; /* backend netns is only known by zebra * for other daemons, we return VRF_DEFAULT_INTERNAL */ diff --git a/lib/vrf.h b/lib/vrf.h index 56ba101ff0..7fb3f7ec81 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -41,8 +41,6 @@ enum { IFLA_VRF_UNSPEC, IFLA_VRF_TABLE, __IFLA_VRF_MAX }; #define VRF_NAMSIZ 36 #define NS_NAMSIZ 16 -#define VRF_DEFAULT_NAME "Default-IP-Routing-Table" - /* * The command strings */ @@ -236,6 +234,10 @@ extern vrf_id_t vrf_get_default_id(void); /* The default VRF ID */ #define VRF_DEFAULT vrf_get_default_id() +extern void vrf_set_default_name(const char *default_name); +extern const char *vrf_get_default_name(void); +#define VRF_DEFAULT_NAME vrf_get_default_name() + /* VRF is mapped on netns or not ? */ int vrf_is_mapped_on_netns(struct vrf *vrf); From 723001fc13a87c5599933a727baf4a152f0e9f7e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Jun 2018 14:32:01 +0200 Subject: [PATCH 02/13] lib: autocomple vrf list authorises default vrf name Now it is possible to dump default vrf information by its name. Signed-off-by: Philippe Guibert --- lib/vrf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index 8778d93f05..b7c5e5e9a6 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -447,10 +447,8 @@ static void vrf_autocomplete(vector comps, struct cmd_token *token) { struct vrf *vrf = NULL; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if (vrf->vrf_id != VRF_DEFAULT) - vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name)); - } + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name)); } static const struct cmd_variable_handler vrf_var_handlers[] = { From ecbc5a37815987aebabae835366b1f2ea18fb3b2 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 29 May 2018 11:17:10 +0200 Subject: [PATCH 03/13] *: add a vrf update hook to be informed of the vrf name The Vrf aliases can be known with a specific hook. That hook will then, from zebra propagate the information to the relevant zapi clients. The registration hook function is the same for all daemons. Signed-off-by: Philippe Guibert --- bgpd/bgp_main.c | 3 ++- eigrpd/eigrp_main.c | 2 +- isisd/isis_main.c | 2 +- ldpd/ldpd.c | 2 +- lib/vrf.c | 7 ++++++- lib/vrf.h | 6 ++++-- nhrpd/nhrp_main.c | 2 +- ospf6d/ospf6_main.c | 2 +- ospfd/ospfd.c | 2 +- pbrd/pbr_main.c | 2 +- pimd/pim_instance.c | 3 ++- ripd/rip_main.c | 2 +- ripngd/ripng_main.c | 2 +- sharpd/sharp_main.c | 2 +- staticd/static_vrf.c | 2 +- tests/bgpd/test_capability.c | 2 +- tests/bgpd/test_mp_attr.c | 2 +- tests/bgpd/test_mpath.c | 2 +- tests/bgpd/test_packet.c | 2 +- tests/bgpd/test_peer_attr.c | 2 +- zebra/zebra_vrf.c | 15 ++++++++++++++- 21 files changed, 44 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 138788194d..2308a32a23 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -332,7 +332,8 @@ static int bgp_vrf_disable(struct vrf *vrf) static void bgp_vrf_init(void) { - vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete); + vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, + bgp_vrf_delete, NULL); } static void bgp_vrf_terminate(void) diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 31101a52d4..9e9c4649fc 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -170,7 +170,7 @@ int main(int argc, char **argv, char **envp) master = eigrp_om->master; eigrp_error_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); /*EIGRPd init*/ eigrp_if_init(); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 5b18ab0a2c..3b4168adb9 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -192,7 +192,7 @@ int main(int argc, char **argv, char **envp) */ isis_error_init(); access_list_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); prefix_list_init(); isis_init(); isis_circuit_init(); diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index e830263ded..935e959596 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -330,7 +330,7 @@ main(int argc, char *argv[]) master = frr_init(); vty_config_lockless(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); access_list_init(); ldp_vty_init(); ldp_zebra_init(master); diff --git a/lib/vrf.c b/lib/vrf.c index b7c5e5e9a6..0bb6a65bf6 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -71,6 +71,7 @@ struct vrf_master { int (*vrf_delete_hook)(struct vrf *); int (*vrf_enable_hook)(struct vrf *); int (*vrf_disable_hook)(struct vrf *); + int (*vrf_update_name_hook)(struct vrf *vrf); } vrf_master = { 0, }; @@ -461,7 +462,8 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { /* Initialize VRF module. */ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), - int (*disable)(struct vrf *), int (*delete)(struct vrf *)) + int (*disable)(struct vrf *), int (*delete)(struct vrf *), + int ((*update)(struct vrf *))) { struct vrf *default_vrf; @@ -475,6 +477,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_enable_hook = enable; vrf_master.vrf_disable_hook = disable; vrf_master.vrf_delete_hook = delete; + vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME); @@ -897,6 +900,8 @@ void vrf_set_default_name(const char *default_name) vrf_default_name, NS_NAMSIZ); strlcpy(def_vrf->name, vrf_default_name, sizeof(def_vrf->name)); RB_INSERT(vrf_name_head, &vrfs_by_name, def_vrf); + if (vrf_master.vrf_update_name_hook) + (*vrf_master.vrf_update_name_hook)(def_vrf); } } diff --git a/lib/vrf.h b/lib/vrf.h index 7fb3f7ec81..c962ac4c69 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -199,8 +199,10 @@ extern int vrf_bitmap_check(vrf_bitmap_t, vrf_id_t); * delete -> Called back when a vrf is being deleted from * the system ( 2 and 3 ) above. */ -extern void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), - int (*disable)(struct vrf *), int (*delete)(struct vrf *)); +extern void vrf_init(int (*create)(struct vrf *vrf), int (*enable)(struct vrf *vrf), + int (*disable)(struct vrf *vrf), int (*delete)(struct vrf *vrf), + int ((*update)(struct vrf *vrf))); + /* * Call vrf_terminate when the protocol is being shutdown */ diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index e9f44e8558..737e70103e 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -130,7 +130,7 @@ int main(int argc, char **argv) /* Library inits. */ master = frr_init(); nhrp_error_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); nhrp_interface_init(); resolver_init(); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 9580d87cf0..eadc856cac 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -208,7 +208,7 @@ int main(int argc, char *argv[], char *envp[]) /* thread master */ master = frr_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); access_list_init(); prefix_list_init(); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index bfaedf2fe7..62de94a475 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -2149,7 +2149,7 @@ static int ospf_vrf_disable(struct vrf *vrf) void ospf_vrf_init(void) { vrf_init(ospf_vrf_new, ospf_vrf_enable, ospf_vrf_disable, - ospf_vrf_delete); + ospf_vrf_delete, NULL); } void ospf_vrf_terminate(void) diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c index ba09621083..f555ccc056 100644 --- a/pbrd/pbr_main.c +++ b/pbrd/pbr_main.c @@ -146,7 +146,7 @@ int main(int argc, char **argv, char **envp) pbr_debug_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); nexthop_group_init(pbr_nhgroup_add_cb, pbr_nhgroup_add_nexthop_cb, pbr_nhgroup_del_nexthop_cb, diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 8dc48cc004..bf8d05d1e1 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -196,7 +196,8 @@ static int pim_vrf_config_write(struct vty *vty) void pim_vrf_init(void) { - vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete); + vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, + pim_vrf_delete, NULL); vrf_cmd_init(pim_vrf_config_write, &pimd_privs); } diff --git a/ripd/rip_main.c b/ripd/rip_main.c index e5a5c3e227..16087c2349 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -170,7 +170,7 @@ int main(int argc, char **argv) /* Library initialization. */ rip_error_init(); keychain_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); /* RIP related initialization. */ rip_init(); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index e4501d6f80..bc81a956d6 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -166,7 +166,7 @@ int main(int argc, char **argv) master = frr_init(); /* Library inits. */ - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); /* RIPngd inits. */ ripng_init(); diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index f0e6e3db4a..65b1837f68 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -146,7 +146,7 @@ int main(int argc, char **argv, char **envp) master = frr_init(); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); access_list_init(); route_map_init(); diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index 6946f21271..d33c1539c8 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -190,7 +190,7 @@ int static_vrf_has_config(struct static_vrf *svrf) void static_vrf_init(void) { vrf_init(static_vrf_new, static_vrf_enable, - static_vrf_disable, static_vrf_delete); + static_vrf_disable, static_vrf_delete, NULL); vrf_cmd_init(static_vrf_config_write, &static_privs); } diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index fef7d39ff5..83af5e9c6d 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -913,7 +913,7 @@ int main(void) qobj_init(); master = thread_master_create(NULL); bgp_master_init(master); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); bgp_pthreads_init(); diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index 8db1cb2ca1..603b678cf1 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1079,7 +1079,7 @@ int main(void) bgp_vty_init(); master = thread_master_create("test mp attr"); bgp_master_init(master); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); bgp_attr_init(); diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index d8d2286bf7..42f7d76759 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -379,7 +379,7 @@ static int global_test_init(void) master = thread_master_create(NULL); zclient = zclient_new_notify(master, &zclient_options_default); bgp_master_init(master); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); if (fileno(stdout) >= 0) diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c index c58a85eed3..9719aceec9 100644 --- a/tests/bgpd/test_packet.c +++ b/tests/bgpd/test_packet.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) bgp_attr_init(); master = thread_master_create(NULL); bgp_master_init(master); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT)) diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 16bd5d96da..452245ec16 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1387,7 +1387,7 @@ static void bgp_startup(void) master = thread_master_create(NULL); bgp_master_init(master); bgp_option_set(BGP_OPT_NO_LISTEN); - vrf_init(NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_init(); bgp_pthreads_run(); } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 05ae418b57..be8f879246 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -282,6 +282,19 @@ static int zebra_vrf_delete(struct vrf *vrf) return 0; } +static int zebra_vrf_update(struct vrf *vrf) +{ + struct zebra_vrf *zvrf = vrf->info; + + assert(zvrf); + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("VRF %s id %u, name updated", vrf->name, + zvrf_id(zvrf)); + zebra_vrf_add_update(zvrf); + return 0; +} + + /* Return if this VRF has any FRR configuration or not. * IMPORTANT: This function needs to be updated when additional configuration * is added for a VRF. @@ -491,7 +504,7 @@ static int vrf_config_write(struct vty *vty) void zebra_vrf_init(void) { vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, - zebra_vrf_delete); + zebra_vrf_delete, zebra_vrf_update); vrf_cmd_init(vrf_config_write, &zserv_privs); } From 3ed78e8cff9d141ccd1f917566637d7bf3e4bb0d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Jun 2018 13:55:55 +0200 Subject: [PATCH 04/13] zebra: detect if a netns is the default netns In the case the default netns has a netns path, then a new NETNS creation will be bypassed. Signed-off-by: Philippe Guibert --- zebra/zebra_netns_notify.c | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 2b7bf04ec3..12207805d9 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -149,6 +149,41 @@ static int zebra_ns_delete(char *name) return 0; } +static int zebra_ns_notify_self_identify(struct stat *netst) +{ + char net_path[64]; + int netns; + + sprintf(net_path, "/proc/self/ns/net"); + netns = open(net_path, O_RDONLY); + if (netns < 0) + return -1; + if (fstat(netns, netst) < 0) { + close(netns); + return -1; + } + close(netns); + return 0; +} + +static bool zebra_ns_notify_is_default_netns(const char *name) +{ + struct stat default_netns_stat; + struct stat st; + char netnspath[64]; + + if (zebra_ns_notify_self_identify(&default_netns_stat)) + return false; + + memset(&st, 0, sizeof(struct stat)); + snprintf(netnspath, 64, "%s/%s", NS_RUN_DIR, name); + /* compare with local stat */ + if (stat(netnspath, &st) == 0 && + (st.st_dev == default_netns_stat.st_dev) && + (st.st_ino == default_netns_stat.st_ino)) + return true; + return false; +} static int zebra_ns_ready_read(struct thread *t) { @@ -178,6 +213,14 @@ static int zebra_ns_ready_read(struct thread *t) if (err < 0) return zebra_ns_continue_read(zns_info, stop_retry); + if (zebra_ns_notify_is_default_netns(basename(netnspath))) { + zlog_warn( + "NS notify : NS %s is default VRF." + " Updating VRF Name", basename(netnspath)); + vrf_set_default_name(basename(netnspath)); + return zebra_ns_continue_read(zns_info, 1); + } + /* success : close fd and create zns context */ zebra_ns_notify_create_context_from_entry_name(basename(netnspath)); return zebra_ns_continue_read(zns_info, 1); @@ -259,6 +302,13 @@ void zebra_ns_notify_parse(void) dent->d_name); continue; } + if (zebra_ns_notify_is_default_netns(dent->d_name)) { + zlog_warn( + "NS notify : NS %s is default VRF." + " Updating VRF Name", dent->d_name); + vrf_set_default_name(dent->d_name); + continue; + } zebra_ns_notify_create_context_from_entry_name(dent->d_name); } closedir(srcdir); From 6a8ca00fa01c3368f536b122cbe608fc828a3642 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Jun 2018 14:32:35 +0200 Subject: [PATCH 05/13] bgpd: authorize default vrf name usage Now it is possible to configure BGP default instance by using its default vrf name. Signed-off-by: Philippe Guibert --- bgpd/bgpd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 7ff5053ce3..5d258a765b 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7735,10 +7735,8 @@ static void bgp_viewvrf_autocomplete(vector comps, struct cmd_token *token) struct listnode *next; struct bgp *bgp; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if (vrf->vrf_id != VRF_DEFAULT) - vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name)); - } + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name)); for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { if (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) From 6895b354ef88b30e41c92c0d6efa75cd05dba52a Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 6 Jun 2018 10:13:44 +0200 Subject: [PATCH 06/13] ospfd: adaptations to handle vrf alias Some adaptations are done to handle alias when creationg ospf instance. Signed-off-by: Philippe Guibert --- ospfd/ospf_vty.c | 2 ++ ospfd/ospfd.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index fb9770d09a..39f14a00c3 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -145,6 +145,8 @@ static struct ospf *ospf_cmd_lookup_ospf(struct vty *vty, if (argv_find(argv, argc, "vrf", &idx_vrf)) { vrf_name = argv[idx_vrf + 1]->arg; + if (vrf_name == NULL || strmatch(vrf_name, VRF_DEFAULT_NAME)) + vrf_name = NULL; if (enable) { /* Allocate VRF aware instance */ ospf = ospf_get(*instance, vrf_name); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 62de94a475..d311b4da6b 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -234,12 +234,10 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) new->instance = instance; new->router_id.s_addr = htonl(0); new->router_id_static.s_addr = htonl(0); - - if (name) { + if (name && !strmatch(name, VRF_DEFAULT_NAME)) { new->vrf_id = VRF_UNKNOWN; /* Freed in ospf_finish_final */ new->name = XSTRDUP(MTYPE_OSPF_TOP, name); - vrf = vrf_lookup_by_name(new->name); if (IS_DEBUG_OSPF_EVENT) zlog_debug( "%s: Create new ospf instance with vrf_name %s vrf_id %u", @@ -381,6 +379,9 @@ struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name) struct ospf *ospf = NULL; struct listnode *node, *nnode; + if (name == NULL || strmatch(name, VRF_DEFAULT_NAME)) + return ospf_lookup_by_vrf_id(VRF_DEFAULT); + for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf)) { if ((ospf->instance == instance) && ((ospf->name == NULL && name == NULL) @@ -2078,6 +2079,10 @@ static int ospf_vrf_enable(struct vrf *vrf) ospf = ospf_lookup_by_name(vrf->name); if (ospf) { + if (ospf->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { + XFREE(MTYPE_OSPF_TOP, ospf->name); + ospf->name = NULL; + } old_vrf_id = ospf->vrf_id; /* We have instance configured, link to VRF and make it "up". */ ospf_vrf_link(ospf, vrf); From 9a8bdf1c25180e7c00b525c6c8de26cc2f713fb2 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 31 May 2018 10:12:11 +0200 Subject: [PATCH 07/13] bgpd: handle vrf aliases in vty API Because a VRF name can be used for default VRF, or an alias of an already created VRF can be passed as parameter, the default VRF name must be found out. This avoids creating double BGP instances for example. Signed-off-by: Philippe Guibert --- bgpd/bgp_main.c | 6 +++ bgpd/bgp_vty.c | 112 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 2308a32a23..e0834604b2 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -266,6 +266,12 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp = bgp_lookup_by_name(vrf->name); if (bgp) { + if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { + XFREE(MTYPE_BGP, bgp->name); + bgp->name = NULL; + XFREE(MTYPE_BGP, bgp->name_pretty); + bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default"); + } old_vrf_id = bgp->vrf_id; /* We have instance configured, link to VRF and make it "up". */ bgp_vrf_link(bgp, vrf); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1460a26215..99c6f39230 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -312,10 +312,14 @@ int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, if (argv_find(argv, argc, "ip", idx)) *afi = AFI_IP; - if (argv_find(argv, argc, "view", idx) - || argv_find(argv, argc, "vrf", idx)) { + if (argv_find(argv, argc, "view", idx)) vrf_name = argv[*idx + 1]->arg; - + else if (argv_find(argv, argc, "vrf", idx)) { + vrf_name = argv[*idx + 1]->arg; + if (strmatch(vrf_name, VRF_DEFAULT_NAME)) + vrf_name = NULL; + } + if (vrf_name) { if (strmatch(vrf_name, "all")) *bgp = NULL; else { @@ -910,9 +914,12 @@ DEFUN_NOSH (router_bgp, if (argc > 3) { name = argv[idx_vrf]->arg; - if (!strcmp(argv[idx_view_vrf]->text, "vrf")) - inst_type = BGP_INSTANCE_TYPE_VRF; - else if (!strcmp(argv[idx_view_vrf]->text, "view")) + if (!strcmp(argv[idx_view_vrf]->text, "vrf")) { + if (strmatch(name, VRF_DEFAULT_NAME)) + name = NULL; + else + inst_type = BGP_INSTANCE_TYPE_VRF; + } else if (!strcmp(argv[idx_view_vrf]->text, "view")) inst_type = BGP_INSTANCE_TYPE_VIEW; } @@ -7144,13 +7151,17 @@ DEFUN (clear_ip_bgp_all, if (argv_find(argv, argc, "ip", &idx)) afi = AFI_IP; - /* [ VIEWVRFNAME] */ - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) { + /* [ VIEWVRFNAME] */ + if (argv_find(argv, argc, "vrf", &idx)) { + vrf = argv[idx + 1]->arg; + idx += 2; + if (vrf && strmatch(vrf, VRF_DEFAULT_NAME)) + vrf = NULL; + } else if (argv_find(argv, argc, "view", &idx)) { + /* [ VIEWVRFNAME] */ vrf = argv[idx + 1]->arg; idx += 2; } - /* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */ if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) argv_find_and_parse_safi(argv, argc, &idx, &safi); @@ -7215,8 +7226,16 @@ DEFUN (clear_ip_bgp_prefix, int idx = 0; /* [ VIEWVRFNAME] */ - if (argv_find(argv, argc, "VIEWVRFNAME", &idx)) - vrf = argv[idx]->arg; + if (argv_find(argv, argc, "vrf", &idx)) { + vrf = argv[idx + 1]->arg; + idx += 2; + if (vrf && strmatch(vrf, VRF_DEFAULT_NAME)) + vrf = NULL; + } else if (argv_find(argv, argc, "view", &idx)) { + /* [ VIEWVRFNAME] */ + vrf = argv[idx + 1]->arg; + idx += 2; + } prefix = argv[argc - 1]->arg; @@ -7258,16 +7277,23 @@ DEFUN (clear_bgp_instance_ipv6_safi_prefix, "Clear bestpath and re-advertise\n" "IPv6 prefix\n") { - int idx_word = 3; int idx_safi = 0; + int idx_vrfview = 0; int idx_ipv6_prefix = 0; safi_t safi = SAFI_UNICAST; char *prefix = argv_find(argv, argc, "X:X::X:X/M", &idx_ipv6_prefix) ? argv[idx_ipv6_prefix]->arg : NULL; - /* [ VIEWVRFNAME] */ - char *vrfview = argv_find(argv, argc, "VIEWVRFNAME", &idx_word) ? - argv[idx_word]->arg : NULL; + char *vrfview = NULL; + /* [ VIEWVRFNAME] */ + if (argv_find(argv, argc, "vrf", &idx_vrfview)) { + vrfview = argv[idx_vrfview + 1]->arg; + if (vrfview && strmatch(vrfview, VRF_DEFAULT_NAME)) + vrfview = NULL; + } else if (argv_find(argv, argc, "view", &idx_vrfview)) { + /* [ VIEWVRFNAME] */ + vrfview = argv[idx_vrfview + 1]->arg; + } argv_find_and_parse_safi(argv, argc, &idx_safi, &safi); return bgp_clear_prefix( @@ -7458,10 +7484,18 @@ DEFUN(show_bgp_martian_nexthop_db, show_bgp_martian_nexthop_db_cmd, { struct bgp *bgp = NULL; int idx = 0; + char *name = NULL; - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - bgp = bgp_lookup_by_name(argv[idx + 1]->arg); + /* [ VIEWVRFNAME] */ + if (argv_find(argv, argc, "vrf", &idx)) { + name = argv[idx + 1]->arg; + if (name && strmatch(name, VRF_DEFAULT_NAME)) + name = NULL; + } else if (argv_find(argv, argc, "view", &idx)) + /* [ VIEWVRFNAME] */ + name = argv[idx + 1]->arg; + if (name) + bgp = bgp_lookup_by_name(name); else bgp = bgp_get_default(); @@ -8211,10 +8245,14 @@ DEFUN (show_ip_bgp_summary, /* show [ip] bgp */ if (argv_find(argv, argc, "ip", &idx)) afi = AFI_IP; - /* [ VIEWVRFNAME] */ - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; + /* [ VIEWVRFNAME] */ + if (argv_find(argv, argc, "vrf", &idx)) { + vrf = argv[idx + 1]->arg; + if (vrf && strmatch(vrf, VRF_DEFAULT_NAME)) + vrf = NULL; + } else if (argv_find(argv, argc, "view", &idx)) + /* [ VIEWVRFNAME] */ + vrf = argv[idx + 1]->arg; /* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */ if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { argv_find_and_parse_safi(argv, argc, &idx, &safi); @@ -10888,8 +10926,13 @@ DEFUN (show_ip_bgp_neighbors, int idx = 0; - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) + /* [ VIEWVRFNAME] */ + if (argv_find(argv, argc, "vrf", &idx)) { + vrf = argv[idx + 1]->arg; + if (vrf && strmatch(vrf, VRF_DEFAULT_NAME)) + vrf = NULL; + } else if (argv_find(argv, argc, "view", &idx)) + /* [ VIEWVRFNAME] */ vrf = argv[idx + 1]->arg; idx++; @@ -11183,8 +11226,11 @@ DEFUN (show_ip_bgp_route_leak, return CMD_WARNING; } - if (argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; + if (argv_find(argv, argc, "vrf", &idx)) { + vrf = argv[idx + 1]->arg; + if (vrf && strmatch(vrf, VRF_DEFAULT_NAME)) + vrf = NULL; + } /* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */ if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { argv_find_and_parse_safi(argv, argc, &idx, &safi); @@ -11257,10 +11303,14 @@ DEFUN (show_ip_bgp_updgrps, /* show [ip] bgp */ if (argv_find(argv, argc, "ip", &idx)) afi = AFI_IP; - /* [ VIEWVRFNAME] */ - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; + /* [ VIEWVRFNAME] */ + if (argv_find(argv, argc, "vrf", &idx)) { + vrf = argv[idx + 1]->arg; + if (vrf && strmatch(vrf, VRF_DEFAULT_NAME)) + vrf = NULL; + } else if (argv_find(argv, argc, "view", &idx)) + /* [ VIEWVRFNAME] */ + vrf = argv[idx + 1]->arg; /* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */ if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { argv_find_and_parse_safi(argv, argc, &idx, &safi); From fdafe17ee9b491ecc20693c1da1c96db22bc6dda Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 27 Jun 2018 18:23:09 +0200 Subject: [PATCH 08/13] lib: set default vrf name at startup For the daemons that do not use vrf_init(), the call to the define will return a default vrf if no other values has been overriden. Signed-off-by: Philippe Guibert --- lib/vrf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/vrf.c b/lib/vrf.c index 0bb6a65bf6..8ae59f5065 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -466,7 +466,10 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), int ((*update)(struct vrf *))) { struct vrf *default_vrf; + char *local_ptr = (char *)VRF_DEFAULT_NAME; + if (local_ptr) + vrf_default_name = XSTRDUP(MTYPE_VRF, local_ptr); /* initialise NS, in case VRF backend if NETNS */ ns_init(); if (debug_vrf) @@ -480,12 +483,15 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ - default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME); + default_vrf = vrf_get(VRF_DEFAULT, vrf_default_name); if (!default_vrf) { flog_err(LIB_ERR_VRF_START, "vrf_init: failed to create the default VRF!"); exit(1); } + if (vrf_is_backend_netns()) + strlcpy(default_vrf->data.l.netns_name, + vrf_default_name, NS_NAMSIZ); /* Enable the default VRF. */ if (!vrf_enable(default_vrf)) { From dd1147028ad9e461644116b68b38f31b26b4bd2d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Jun 2018 16:03:11 +0200 Subject: [PATCH 09/13] lib: protect newly created vrfs against default vrf naming. Prevent from creating vrf, if the default vrf name is the same as the vrf to be created. Also, prevent at startup from creating default vrf with a name already used in vrf list. Signed-off-by: Philippe Guibert --- lib/vrf.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/vrf.c b/lib/vrf.c index 8ae59f5065..f74e233877 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -39,7 +39,7 @@ /* default VRF ID value used when VRF backend is not NETNS */ #define VRF_DEFAULT_INTERNAL 0 -#define VRF_DEFAULT_NAME_INTERNAL "Default-IP-Routing-Table" +#define VRF_DEFAULT_NAME_INTERNAL "default" DEFINE_MTYPE_STATIC(LIB, VRF, "VRF") DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map") @@ -168,6 +168,13 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) */ if (name) vrf = vrf_lookup_by_name(name); + if (vrf && vrf_id != VRF_UNKNOWN + && vrf->vrf_id != VRF_UNKNOWN + && vrf->vrf_id != vrf_id) { + zlog_debug("VRF_GET: avoid %s creation(%u), same name exists (%u)", + name, vrf_id, vrf->vrf_id); + return NULL; + } /* Try to find VRF both by ID and name */ if (!vrf && vrf_id != VRF_UNKNOWN) vrf = vrf_lookup_by_id(vrf_id); @@ -888,6 +895,7 @@ void vrf_cmd_init(int (*writefunc)(struct vty *vty), void vrf_set_default_name(const char *default_name) { struct vrf *def_vrf; + struct vrf *vrf_with_default_name = NULL; def_vrf = vrf_lookup_by_id(VRF_DEFAULT); assert(default_name); From eb6934d5c5a1937ab2d8ecab5dd5b8242f1fda3f Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 4 Jul 2018 17:30:14 +0200 Subject: [PATCH 10/13] lib: avoid default vrf name memory allocation at startup If default VRF is used, with standard naming convention, memory allocation can be avoided. Signed-off-by: Philippe Guibert --- lib/vrf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index f74e233877..1fb1b786c7 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -473,10 +473,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), int ((*update)(struct vrf *))) { struct vrf *default_vrf; - char *local_ptr = (char *)VRF_DEFAULT_NAME; - if (local_ptr) - vrf_default_name = XSTRDUP(MTYPE_VRF, local_ptr); /* initialise NS, in case VRF backend if NETNS */ ns_init(); if (debug_vrf) @@ -490,7 +487,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ - default_vrf = vrf_get(VRF_DEFAULT, vrf_default_name); + default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME); if (!default_vrf) { flog_err(LIB_ERR_VRF_START, "vrf_init: failed to create the default VRF!"); @@ -498,7 +495,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), } if (vrf_is_backend_netns()) strlcpy(default_vrf->data.l.netns_name, - vrf_default_name, NS_NAMSIZ); + VRF_DEFAULT_NAME, NS_NAMSIZ); /* Enable the default VRF. */ if (!vrf_enable(default_vrf)) { From c94e67258c220e72d9840a2a445e10099330f147 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Jun 2018 16:01:07 +0200 Subject: [PATCH 11/13] doc: add information about dynamic update of default vrf name It is possible to dynamically change default VRF name, if vrf backend is a netns backend. By creating a link to the default netns in /var/run/netns folder, then the file name will be used to name the default VRF. If no backend netns is chosen, it is explained that it is still possible to statically configure the default vrf name to new define. Signed-off-by: Philippe Guibert --- doc/user/zebra.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index af8e4b8d47..8a394928c6 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -355,6 +355,40 @@ commands in relationship to VRF. Here is an extract of some of those commands: will dump the routing table ``TABLENO`` of the *Linux network namespace* ``VRF``. +By using the :option:`-n` option, the *Linux network namespace* will be mapped +over the *Zebra* VRF. One nice feature that is possible by handling *Linux +network namespace* is the ability to name default VRF. At startup, *Zebra* +discovers the available *Linux network namespace* by parsing folder +`/var/run/netns`. Each file stands for a *Linux network namespace*, but not all +*Linux network namespaces* are available under that folder. This is the case for +default VRF. It is possible to name the default VRF, by creating a file, by +executing following commands. + +.. code-block:: shell + + touch /var/run/netns/vrf0 + mount --bind /proc/self/ns/net /var/run/netns/vrf0 + +Above command illustrates what happens when the default VRF is visible under +`var/run/netns/`. Here, the default VRF file is `vrf0`. +At startup, FRR detects the presence of that file. It detects that the file +statistics information matches the same file statistics information as +`/proc/self/ns/net` ( through stat() function). As statistics information +matches, then `vrf0` stands for the new default namespace name. +Consequently, the VRF naming `Default` will be overriden by the new discovered +namespace name `vrf0`. + +For those who don't use VRF backend with *Linux network namespace*, it is +possible to statically configure and recompile FRR. It is possible to choose an +alternate name for default VRF. Then, the default VRF naming will automatically +be updated with the new name. To illustrate, if you want to recompile with +`global` value, use the following command: + +.. code-block:: linux + + ./configure --with-defaultvrfname=global + +More information about the option in :ref:`_frr-configuration`. .. _zebra-mpls: From cc6743c290d88107f316917dcda706332477c8ff Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 25 Jul 2018 09:38:56 +0200 Subject: [PATCH 12/13] zebra: add an option to zebra command to change default vrf name There is a possibility to change the default vrf name, using the '-o' option. Signed-off-by: Philippe Guibert --- doc/user/zebra.rst | 7 +++++++ zebra/main.c | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 8a394928c6..85f2a7af3e 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -48,6 +48,13 @@ Besides the common invocation options (:ref:`common-invocation-options`), the .. seealso:: :ref:`zebra-vrf` +.. option:: -o, --vrfdefaultname + + When *Zebra* starts with this option, the default VRF name is changed to the + parameter. + + .. seealso:: :ref:`zebra-vrf` + .. option:: --v6-rr-semantics The linux kernel is receiving the ability to use the same route diff --git a/zebra/main.c b/zebra/main.c index 5e7c69382f..8db1c48f22 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -99,6 +99,7 @@ struct option longopts[] = { {"ecmp", required_argument, NULL, 'e'}, {"label_socket", no_argument, NULL, 'l'}, {"retain", no_argument, NULL, 'r'}, + {"vrfdefaultname", required_argument, NULL, 'o'}, #ifdef HAVE_NETLINK {"vrfwnetns", no_argument, NULL, 'n'}, {"nl-bufsize", required_argument, NULL, 's'}, @@ -235,7 +236,7 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); frr_opt_add( - "bakz:e:l:r" + "bakz:e:l:o:r" #ifdef HAVE_NETLINK "s:n" #endif @@ -254,6 +255,7 @@ int main(int argc, char **argv) " -l, --label_socket Socket to external label manager\n" " -k, --keep_kernel Don't delete old routes which were installed by zebra.\n" " -r, --retain When program terminates, retain added route by zebra.\n" + " -o, --vrfdefaultname Set default VRF name.\n" #ifdef HAVE_NETLINK " -n, --vrfwnetns Use NetNS as VRF backend\n" " -s, --nl-bufsize Set netlink receive buffer size\n" @@ -296,6 +298,9 @@ int main(int argc, char **argv) return 1; } break; + case 'o': + vrf_set_default_name(optarg); + break; case 'z': zserv_path = optarg; if (!frr_zclient_addr(&dummy, &dummylen, optarg)) { From 4931a3659acc8fc59379ee85ecb65b02509ae940 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 28 Aug 2018 10:37:56 +0200 Subject: [PATCH 13/13] lib: overwrite default vrf name upon zapi vrf add event The default vrf name is overwritten, upon reception of zapi vrf event. Signed-off-by: Philippe Guibert --- lib/zclient.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index b2bafcb7d8..c5a48c178a 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1366,6 +1366,9 @@ static void zclient_vrf_add(struct zclient *zclient, vrf_id_t vrf_id) vrf = vrf_get(vrf_id, vrfname_tmp); vrf->data.l.table_id = data.l.table_id; memcpy(vrf->data.l.netns_name, data.l.netns_name, NS_NAMSIZ); + /* overwrite default vrf */ + if (vrf_id == VRF_DEFAULT) + vrf_set_default_name(vrfname_tmp); vrf_enable(vrf); }