From 84915b0a15e32a51622f28b6bcafff58a4b02d6d Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Dec 2017 17:36:37 -0800 Subject: *: Handle VRF configuration when VRF gets inactivated and activated A VRF is active only when the corresponding VRF device is present in the kernel. However, when the kernel VRF device is removed, the VRF container in FRR should go away only if there is no user configuration for it. Otherwise, when the VRF device is created again so that the VRF becomes active, FRR cannot take the correct actions. Example configuration for the VRF includes static routes and EVPN L3 VNI. Note that a VRF is currently considered to be "configured" as soon as the operator has issued the "vrf " command in FRR. Such a configured VRF is not deleted upon VRF device removal, it is only made inactive. A VRF that is "configured" can be deleted only upon operator action and only if the VRF has been deactivated i.e., the VRF device removed from the kernel. This is an existing restriction. To implement this change, the VRF disable and delete actions have been modified. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Mitesh Kanjariya Reviewed-by: Don Slice Ticket: CM-18553, CM-18918, CM-10139 Reviewed By: CCR-7022 Testing Done: 1. vrf and pim-vrf automation tests 2. Multiple VRF delete and readd (ifdown, ifup-with-depends) 3. FRR stop, start, restart 4. Networking restart 5. Configuration delete and readd Some of the above tests run in different sequences (manually). --- lib/vrf.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'lib/vrf.c') diff --git a/lib/vrf.c b/lib/vrf.c index 2fa3a9c0ef..bc081796c5 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -141,7 +141,9 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) return vrf; } -/* Delete a VRF. This is called in vrf_terminate(). */ +/* Delete a VRF. This is called when the underlying VRF goes away, a + * pre-configured VRF is deleted or when shutting down (vrf_terminate()). + */ void vrf_delete(struct vrf *vrf) { if (debug_vrf) @@ -150,6 +152,23 @@ void vrf_delete(struct vrf *vrf) if (vrf_is_enabled(vrf)) vrf_disable(vrf); + /* If the VRF is user configured, it'll stick around, just remove + * the ID mapping. Interfaces assigned to this VRF should've been + * removed already as part of the VRF going down. + */ + if (vrf_is_user_cfged(vrf)) { + if (vrf->vrf_id != VRF_UNKNOWN) { + /* Delete any VRF interfaces - should be only + * the VRF itself, other interfaces should've + * been moved out of the VRF. + */ + if_terminate(vrf); + RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); + vrf->vrf_id = VRF_UNKNOWN; + } + return; + } + if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook)(vrf); @@ -172,14 +191,6 @@ struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id) return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf)); } -/* - * Check whether the VRF is enabled. - */ -static int vrf_is_enabled(struct vrf *vrf) -{ - return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE); -} - /* * Enable a VRF - that is, let the VRF be ready to use. * The VRF_ENABLE_HOOK callback will be called to inform @@ -445,6 +456,9 @@ DEFUN_NOSH (vrf, vrfp = vrf_get(VRF_UNKNOWN, vrfname); + /* Mark as user configured. */ + SET_FLAG(vrfp->status, VRF_CONFIGURED); + VTY_PUSH_CONTEXT(VRF_NODE, vrfp); return CMD_SUCCESS; @@ -473,6 +487,8 @@ DEFUN_NOSH (no_vrf, return CMD_WARNING_CONFIG_FAILED; } + /* Clear configured flag and invoke delete. */ + UNSET_FLAG(vrfp->status, VRF_CONFIGURED); vrf_delete(vrfp); return CMD_SUCCESS; -- cgit v1.2.3 From 65c3a7c4e51e6c5e710687e73cfd675e4da5a480 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 4 Dec 2017 13:10:09 -0800 Subject: lib: Handle configured VRFs at termination When shutting down, ensure that all VRFs including "configured" ones are cleaned up properly. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Ticket: CM-19069 Reviewed By: CCR-7011 Testing Done: Manual verification of failed scenario --- lib/vrf.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'lib/vrf.c') diff --git a/lib/vrf.c b/lib/vrf.c index bc081796c5..23eaa042ec 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -419,10 +419,16 @@ void vrf_terminate(void) zlog_debug("%s: Shutting down vrf subsystem", __PRETTY_FUNCTION__); - while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) + while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) { + /* Clear configured flag and invoke delete. */ + UNSET_FLAG(vrf->status, VRF_CONFIGURED); vrf_delete(vrf); - while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) + } + while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) { + /* Clear configured flag and invoke delete. */ + UNSET_FLAG(vrf->status, VRF_CONFIGURED); vrf_delete(vrf); + } } /* Create a socket for the VRF. */ -- cgit v1.2.3 From 22bd3e94979d0c42e9318d96bced01e807b1b7ce Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 6 Dec 2017 15:19:11 -0800 Subject: *: Refine the notion of a configured VRF in FRR Refine the notion of what FRR considers as "configured" VRF. It is no longer based on user just typing "vrf FOO" but when something is actually configured against that VRF. Right now, in zebra, the only configuration against a VRF are static IP routes and EVPN L3 VNI. Whenever a configuration is removed, check and clear the "configured" flag if there is no other configuration for this VRF. When user attempts to configure a static route and the VRF doesn't exist, a VRF is created; the VRF is only active when also defined in the kernel. Updates: 8b73ea7bd479030418ca06eef59d0648d913b620 Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Don Slice Ticket: CM-10139, CM-18553 Reviewed By: CCR-7019 Testing Done: 1. Manual testing for L3 VNI and static routes - FRR restart, networking restart etc. 2. 'vrf' smoke --- lib/vrf.c | 3 --- lib/vrf.h | 14 +++++++++++++- zebra/zebra_vrf.c | 38 +++++++++++++++++++++++++++++++++++--- zebra/zebra_vrf.h | 1 + zebra/zebra_vty.c | 44 ++++++++++++++++++++++++++++++++++++++------ zebra/zebra_vxlan.c | 2 +- 6 files changed, 88 insertions(+), 14 deletions(-) (limited to 'lib/vrf.c') diff --git a/lib/vrf.c b/lib/vrf.c index 23eaa042ec..2e15fa2f5c 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -462,9 +462,6 @@ DEFUN_NOSH (vrf, vrfp = vrf_get(VRF_UNKNOWN, vrfname); - /* Mark as user configured. */ - SET_FLAG(vrfp->status, VRF_CONFIGURED); - VTY_PUSH_CONTEXT(VRF_NODE, vrfp); return CMD_SUCCESS; diff --git a/lib/vrf.h b/lib/vrf.h index 89d2316354..99c048c702 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -76,7 +76,7 @@ struct vrf { /* Zebra internal VRF status */ u_char status; #define VRF_ACTIVE (1 << 0) /* VRF is up in kernel */ -#define VRF_CONFIGURED (1 << 1) /* VRF is configured by user in frr */ +#define VRF_CONFIGURED (1 << 1) /* VRF has some FRR configuration */ /* Interfaces belonging to this VRF */ struct if_name_head ifaces_by_name; @@ -134,6 +134,18 @@ static inline int vrf_is_user_cfged(struct vrf *vrf) return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED); } +/* Mark that VRF has user configuration */ +static inline void vrf_set_user_cfged(struct vrf *vrf) +{ + SET_FLAG(vrf->status, VRF_CONFIGURED); +} + +/* Mark that VRF no longer has any user configuration */ +static inline void vrf_reset_user_cfged(struct vrf *vrf) +{ + UNSET_FLAG(vrf->status, VRF_CONFIGURED); +} + /* * Utilities to obtain the user data */ diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 54c9f573c9..4310bd394d 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -351,6 +351,37 @@ static int zebra_vrf_delete(struct vrf *vrf) 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. + */ +int zebra_vrf_has_config(struct zebra_vrf *zvrf) +{ + afi_t afi; + safi_t safi; + struct route_table *stable; + + /* NOTE: This is a don't care for the default VRF, but we go through + * the motions to keep things consistent. + */ + /* Any static routes? */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + stable = zvrf->stable[afi][safi]; + if (!stable) + continue; + if (route_table_count(stable)) + return 1; + } + } + + /* EVPN L3-VNI? */ + if (zvrf->l3vni) + return 1; + + return 0; +} + /* Lookup the routing table in a VRF based on both VRF-Id and table-id. * NOTE: Table-id is relevant only in the Default VRF. */ @@ -565,14 +596,15 @@ static int vrf_config_write(struct vty *vty) if (vrf_is_user_cfged(vrf)) { vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); + if (zvrf->l3vni) + vty_out(vty, " vni %u\n", zvrf->l3vni); + vty_out(vty, "!\n"); + } static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute"); static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route"); - if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni) - vty_out(vty, " vni %u\n", zvrf->l3vni); - if (vrf->vrf_id != VRF_DEFAULT) vty_out(vty, "!\n"); } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index c7a0717ee8..fe7e77e8be 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -149,5 +149,6 @@ extern struct route_table *zebra_vrf_static_table(afi_t, safi_t, struct zebra_vrf *zvrf); extern struct route_table * zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id, vrf_id_t vrf_id); +extern int zebra_vrf_has_config(struct zebra_vrf *zvrf); extern void zebra_vrf_init(void); #endif diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index bc6a18d3b5..89ae1e81c3 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -231,13 +231,19 @@ static int zebra_static_route_leak(struct vty *vty, type = STATIC_IPV6_GATEWAY; } - if (!negate) + if (!negate) { static_add_route(afi, safi, type, &p, src_p, gatep, ifname, bh_type, tag, distance, zvrf, nh_zvrf, &snh_label); - else + /* Mark as having FRR configuration */ + vrf_set_user_cfged(zvrf->vrf); + } else { static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); + /* If no other FRR config for this VRF, mark accordingly. */ + if (!zebra_vrf_has_config(zvrf)) + vrf_reset_user_cfged(zvrf->vrf); + } return CMD_SUCCESS; } @@ -247,19 +253,39 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, const char *mask_str, const char *src_str, const char *gate_str, const char *ifname, const char *flag_str, const char *tag_str, - const char *distance_str, const char *vrf_id_str, + const char *distance_str, const char *vrf_name, const char *label_str) { struct zebra_vrf *zvrf; + struct vrf *vrf; /* VRF id */ - zvrf = zebra_vrf_lookup_by_name(vrf_id_str); + zvrf = zebra_vrf_lookup_by_name(vrf_name); - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str); + /* When trying to delete, the VRF must exist. */ + if (negate && !zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf_name); return CMD_WARNING_CONFIG_FAILED; } + /* When trying to create, create the VRF if it doesn't exist. + * Note: The VRF isn't active until we hear about it from the kernel. + */ + if (!zvrf) { + vrf = vrf_get(VRF_UNKNOWN, vrf_name); + if (!vrf) { + vty_out(vty, "%% Could not create vrf %s\n", vrf_name); + return CMD_WARNING_CONFIG_FAILED; + } + zvrf = vrf->info; + if (!zvrf) { + vty_out(vty, "%% Could not create vrf-info %s\n", + vrf_name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Mark as having FRR configuration */ + vrf_set_user_cfged(vrf); + } return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi, negate, dest_str, mask_str, src_str, gate_str, ifname, flag_str, tag_str, @@ -2269,6 +2295,8 @@ DEFUN (show_vrf, else vty_out(vty, "id %u table %u", zvrf_id(zvrf), zvrf->table_id); + if (vrf_is_user_cfged(vrf)) + vty_out(vty, " (configured)"); vty_out(vty, "\n"); } @@ -2372,6 +2400,10 @@ DEFUN (no_vrf_vni_mapping, return CMD_WARNING; } + /* If no other FRR config for this VRF, mark accordingly. */ + if (!zebra_vrf_has_config(zvrf)) + vrf_reset_user_cfged(vrf); + return CMD_SUCCESS; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 750dfc4ea8..fb1aebecc3 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3801,7 +3801,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); stream_put(s, p, sizeof(struct prefix)); /* Write packet size. */ -- cgit v1.2.3