Currently, staticd configuration is tightly coupled with VRF existence.
Because of that, it has to use a hack in NB infrastructure to create a
VRF configuration when at least one static route is configured for this
VRF. This hack is incompatible with mgmtd, because mgmtd doesn't execute
configuration callbacks. Because of that, the configuration may become
out of sync between mgmtd and staticd. There are two main cases:
1. Create static route in a VRF. The VRF data node will be created
automatically in staticd by the NB hack, but not in mgmtd.
2. Delete VRF which has some static routes configured. The static route
configuration will be deleted from staticd by the NB hack, but not
from mgmtd.
To fix the problem, decouple configuration of static routes from VRF
configuration. Now it is possible to configure static routes even if the
VRF doesn't exist yet. Once the VRF is created, staticd applies all the
preconfigured routes.
This change also fixes the problem with static routes being preserved in
the system when staticd "control-plane-protocol" container is deleted
but the VRF is still configured.
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
* based on the control plane protocol
*/
DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
+DECLARE_HOOK(routing_create, (struct nb_cb_create_args *args), (args));
+DECLARE_KOOH(routing_destroy, (struct nb_cb_destroy_args *args), (args));
void routing_control_plane_protocols_register_vrf_dependency(void);
DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
+DEFINE_HOOK(routing_create, (struct nb_cb_create_args *args), (args));
+DEFINE_KOOH(routing_destroy, (struct nb_cb_destroy_args *args), (args));
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol
assert(vrf);
nb_running_set_entry(args->dnode, vrf);
}
+ hook_call(routing_create, args);
break;
};
if (args->event != NB_EV_APPLY)
return NB_OK;
+ hook_call(routing_destroy, args);
+
/*
* If dependency on VRF module is registered, then VRF
* pointer was stored and must be cleared.
static void static_bfd_show_json(struct vty *vty)
{
struct json_object *jo, *jo_path, *jo_afi_safi;
- struct vrf *vrf;
+ struct static_vrf *svrf;
jo = json_object_new_object();
jo_path = json_object_new_object();
json_object_object_add(jo, "path-list", jo_path);
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- const struct static_vrf *svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
struct route_table *rt;
jo_afi_safi = json_object_new_array();
void static_bfd_show(struct vty *vty, bool json)
{
- struct vrf *vrf;
+ struct static_vrf *svrf;
if (json) {
static_bfd_show_json(vty);
vty_out(vty, "Showing BFD monitored static routes:\n");
vty_out(vty, "\n Next hops:\n");
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- const struct static_vrf *svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
struct route_table *rt;
- vty_out(vty, " VRF %s IPv4 Unicast:\n", vrf->name);
+ vty_out(vty, " VRF %s IPv4 Unicast:\n", svrf->name);
rt = svrf->stable[AFI_IP][SAFI_UNICAST];
if (rt)
static_bfd_show_path(vty, rt);
- vty_out(vty, "\n VRF %s IPv4 Multicast:\n", vrf->name);
+ vty_out(vty, "\n VRF %s IPv4 Multicast:\n", svrf->name);
rt = svrf->stable[AFI_IP][SAFI_MULTICAST];
if (rt)
static_bfd_show_path(vty, rt);
- vty_out(vty, "\n VRF %s IPv6 Unicast:\n", vrf->name);
+ vty_out(vty, "\n VRF %s IPv6 Unicast:\n", svrf->name);
rt = svrf->stable[AFI_IP6][SAFI_UNICAST];
if (rt)
static_bfd_show_path(vty, rt);
hook_register(routing_conf_event,
routing_control_plane_protocols_name_validate);
-
- routing_control_plane_protocols_register_vrf_dependency();
+ hook_register(routing_create,
+ routing_control_plane_protocols_staticd_create);
+ hook_register(routing_destroy,
+ routing_control_plane_protocols_staticd_destroy);
/*
* We set FRR_NO_SPLIT_CONFIG flag to avoid reading our config, but we
extern const struct frr_yang_module_info frr_staticd_info;
extern const struct frr_yang_module_info frr_staticd_cli_info;
+int routing_control_plane_protocols_staticd_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_staticd_destroy(
+ struct nb_cb_destroy_args *args);
+
/* Mandatory callbacks. */
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
struct nb_cb_create_args *args);
}
return NB_OK;
}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol
+ */
+int routing_control_plane_protocols_staticd_create(struct nb_cb_create_args *args)
+{
+ struct static_vrf *svrf;
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(args->dnode, "vrf");
+ svrf = static_vrf_alloc(vrf);
+ nb_running_set_entry(args->dnode, svrf);
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_staticd_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct static_vrf *svrf;
+ struct route_table *stable;
+ struct route_node *rn;
+ afi_t afi;
+ safi_t safi;
+
+ svrf = nb_running_unset_entry(args->dnode);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ stable = svrf->stable[afi][safi];
+ if (!stable)
+ continue;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn))
+ static_del_route(rn);
+ }
+
+ static_vrf_free(svrf);
+
+ return NB_OK;
+}
+
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
struct nb_cb_create_args *args)
{
- struct vrf *vrf;
- struct static_vrf *s_vrf;
+ struct static_vrf *svrf;
struct route_node *rn;
const struct lyd_node *vrf_dnode;
struct prefix prefix;
case NB_EV_APPLY:
vrf_dnode = yang_dnode_get_parent(args->dnode,
"control-plane-protocol");
- vrf = nb_running_get_entry(vrf_dnode, NULL, true);
- s_vrf = vrf->info;
+ svrf = nb_running_get_entry(vrf_dnode, NULL, true);
yang_dnode_get_prefix(&prefix, args->dnode, "prefix");
afi_safi = yang_dnode_get_string(args->dnode, "afi-safi");
yang_afi_safi_identity2value(afi_safi, &afi, &safi);
- rn = static_add_route(afi, safi, &prefix, NULL, s_vrf);
- if (vrf->vrf_id == VRF_UNKNOWN)
+ rn = static_add_route(afi, safi, &prefix, NULL, svrf);
+ if (!svrf->vrf || svrf->vrf->vrf_id == VRF_UNKNOWN)
snprintf(
args->errmsg, args->errmsg_len,
"Static Route to %s not installed currently because dependent config not fully available",
XFREE(MTYPE_STATIC_PATH, pn);
}
-struct static_nexthop *static_add_nexthop(struct static_path *pn,
- enum static_nh_type type,
- struct ipaddr *ipaddr,
- const char *ifname,
- const char *nh_vrf, uint32_t color)
+struct static_nexthop *
+static_add_nexthop(struct static_path *pn, enum static_nh_type type,
+ struct ipaddr *ipaddr, const char *ifname,
+ const char *nh_vrfname, uint32_t color)
{
struct route_node *rn = pn->rn;
struct static_nexthop *nh;
- struct static_vrf *nh_svrf;
+ struct vrf *nh_vrf;
struct interface *ifp;
struct static_nexthop *cp;
route_lock_node(rn);
- nh_svrf = static_vrf_lookup_by_name(nh_vrf);
+ nh_vrf = vrf_lookup_by_name(nh_vrfname);
/* Make new static route structure. */
nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop));
if (nh->type == STATIC_BLACKHOLE)
nh->bh_type = STATIC_BLACKHOLE_NULL;
- nh->nh_vrf_id = nh_svrf ? nh_svrf->vrf->vrf_id : VRF_UNKNOWN;
- strlcpy(nh->nh_vrfname, nh_vrf, sizeof(nh->nh_vrfname));
+ nh->nh_vrf_id = nh_vrf ? nh_vrf->vrf_id : VRF_UNKNOWN;
+ strlcpy(nh->nh_vrfname, nh_vrfname, sizeof(nh->nh_vrfname));
if (ifname)
strlcpy(nh->ifname, ifname, sizeof(nh->ifname));
struct route_node *rn;
struct static_nexthop *nh;
struct static_path *pn;
- struct vrf *vrf;
+ struct static_vrf *svrf;
struct static_route_info *si;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf;
-
- svrf = vrf->info;
-
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
stable = static_vrf_static_table(afi, safi, svrf);
if (!stable)
continue;
* afi -> The afi to look at
* safi -> the safi to look at
*/
-static void static_fixup_vrf(struct static_vrf *svrf,
- struct route_table *stable, afi_t afi, safi_t safi)
+static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
+ afi_t afi, safi_t safi)
{
struct route_node *rn;
struct static_nexthop *nh;
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (strcmp(svrf->vrf->name, nh->nh_vrfname)
- != 0)
+ if (strcmp(vrf->name, nh->nh_vrfname) != 0)
continue;
- nh->nh_vrf_id = svrf->vrf->vrf_id;
+ nh->nh_vrf_id = vrf->vrf_id;
nh->nh_registered = false;
- if (nh->ifindex) {
+ if (nh->ifname[0]) {
ifp = if_lookup_by_name(nh->ifname,
nh->nh_vrf_id);
if (ifp)
* afi -> the afi in question
* safi -> the safi in question
*/
-static void static_enable_vrf(struct static_vrf *svrf,
- struct route_table *stable, afi_t afi,
- safi_t safi)
+static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi)
{
struct route_node *rn;
struct static_nexthop *nh;
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->ifindex) {
+ if (nh->nh_vrf_id == VRF_UNKNOWN)
+ continue;
+ if (nh->ifname[0]) {
ifp = if_lookup_by_name(nh->ifname,
nh->nh_vrf_id);
if (ifp)
else
continue;
}
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- continue;
+
static_install_path(pn);
}
}
*
* enable_svrf -> the vrf being enabled
*/
-void static_fixup_vrf_ids(struct static_vrf *enable_svrf)
+void static_fixup_vrf_ids(struct vrf *vrf)
{
struct route_table *stable;
- struct vrf *vrf;
+ struct static_vrf *svrf, *enable_svrf;
afi_t afi;
safi_t safi;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf;
+ enable_svrf = vrf->info;
- svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
/* Install any static routes configured for this VRF. */
FOREACH_AFI_SAFI (afi, safi) {
stable = svrf->stable[afi][safi];
if (!stable)
continue;
- static_fixup_vrf(enable_svrf, stable, afi, safi);
+ static_fixup_vrf(vrf, stable, afi, safi);
if (enable_svrf == svrf)
- static_enable_vrf(svrf, stable, afi, safi);
+ static_enable_vrf(stable, afi, safi);
}
}
}
* afi -> the afi in question
* safi -> the safi in question
*/
-static void static_cleanup_vrf(struct static_vrf *svrf,
- struct route_table *stable,
+static void static_cleanup_vrf(struct vrf *vrf, struct route_table *stable,
afi_t afi, safi_t safi)
{
struct route_node *rn;
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (strcmp(svrf->vrf->name, nh->nh_vrfname)
- != 0)
+ if (strcmp(vrf->name, nh->nh_vrfname) != 0)
continue;
static_uninstall_path(pn);
+
+ nh->nh_vrf_id = VRF_UNKNOWN;
+ nh->ifindex = IFINDEX_INTERNAL;
}
}
}
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+ if (nh->nh_vrf_id == VRF_UNKNOWN)
+ continue;
+
static_uninstall_path(pn);
}
}
*
* disable_svrf - The vrf being disabled
*/
-void static_cleanup_vrf_ids(struct static_vrf *disable_svrf)
+void static_cleanup_vrf_ids(struct vrf *vrf)
{
- struct vrf *vrf;
+ struct route_table *stable;
+ struct static_vrf *svrf, *disable_svrf;
afi_t afi;
safi_t safi;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf;
-
- svrf = vrf->info;
+ disable_svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
/* Uninstall any static routes configured for this VRF. */
FOREACH_AFI_SAFI (afi, safi) {
- struct route_table *stable;
-
stable = svrf->stable[afi][safi];
if (!stable)
continue;
- static_cleanup_vrf(disable_svrf, stable, afi, safi);
+ static_cleanup_vrf(vrf, stable, afi, safi);
if (disable_svrf == svrf)
static_disable_vrf(stable, afi, safi);
}
}
-/*
- * This function enables static routes when an interface it relies
- * on in a different vrf is coming up.
- *
- * stable -> The stable we are looking at.
- * ifp -> interface coming up
- * afi -> the afi in question
- * safi -> the safi in question
- */
-static void static_fixup_intf_nh(struct route_table *stable,
- struct interface *ifp,
- afi_t afi, safi_t safi)
-{
- struct route_node *rn;
- struct static_nexthop *nh;
- struct static_path *pn;
- struct static_route_info *si;
-
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- si = static_route_info_from_rnode(rn);
- if (!si)
- continue;
- frr_each(static_path_list, &si->path_list, pn) {
- frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->nh_vrf_id != ifp->vrf->vrf_id)
- continue;
-
- if (nh->ifindex != ifp->ifindex)
- continue;
-
- static_install_path(pn);
- }
- }
- }
-}
-
-/*
- * This function enables static routes that rely on an interface in
- * a different vrf when that interface comes up.
- */
-void static_install_intf_nh(struct interface *ifp)
-{
- struct route_table *stable;
- struct vrf *vrf;
- afi_t afi;
- safi_t safi;
-
- RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf = vrf->info;
-
- /* Not needed if same vrf since happens naturally */
- if (vrf->vrf_id == ifp->vrf->vrf_id)
- continue;
-
- /* Install any static routes configured for this interface. */
- FOREACH_AFI_SAFI (afi, safi) {
- stable = svrf->stable[afi][safi];
- if (!stable)
- continue;
-
- static_fixup_intf_nh(stable, ifp, afi, safi);
- }
- }
-}
-
/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
void static_ifindex_update(struct interface *ifp, bool up)
{
extern struct zebra_privs_t static_privs;
-void static_fixup_vrf_ids(struct static_vrf *svrf);
+extern void static_fixup_vrf_ids(struct vrf *vrf);
+extern void static_cleanup_vrf_ids(struct vrf *vrf);
extern struct static_nexthop *
static_add_nexthop(struct static_path *pn, enum static_nh_type type,
extern void static_delete_nexthop(struct static_nexthop *nh);
-extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf);
-
-extern void static_install_intf_nh(struct interface *ifp);
-
extern void static_ifindex_update(struct interface *ifp, bool up);
extern void static_install_path(struct static_path *pn);
DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info");
-static struct static_vrf *static_vrf_alloc(void)
+static int svrf_name_compare(const struct static_vrf *a,
+ const struct static_vrf *b)
+{
+ return strcmp(a->name, b->name);
+}
+
+RB_GENERATE(svrf_name_head, static_vrf, entry, svrf_name_compare);
+
+struct svrf_name_head svrfs = RB_INITIALIZER(&svrfs);
+
+static struct static_vrf *static_vrf_lookup_by_name(const char *name)
+{
+ struct static_vrf svrf;
+
+ strlcpy(svrf.name, name, sizeof(svrf.name));
+ return RB_FIND(svrf_name_head, &svrfs, &svrf);
+}
+
+struct static_vrf *static_vrf_alloc(const char *name)
{
struct route_table *table;
struct static_vrf *svrf;
struct stable_info *info;
+ struct vrf *vrf;
safi_t safi;
afi_t afi;
svrf = XCALLOC(MTYPE_STATIC_RTABLE_INFO, sizeof(struct static_vrf));
+ strlcpy(svrf->name, name, sizeof(svrf->name));
+
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
if (afi == AFI_IP6)
svrf->stable[afi][safi] = table;
}
}
+
+ RB_INSERT(svrf_name_head, &svrfs, svrf);
+
+ vrf = vrf_lookup_by_name(name);
+ if (vrf) {
+ svrf->vrf = vrf;
+ vrf->info = svrf;
+ }
+
return svrf;
}
+void static_vrf_free(struct static_vrf *svrf)
+{
+ struct route_table *table;
+ struct vrf *vrf;
+ safi_t safi;
+ afi_t afi;
+ void *info;
+
+ vrf = svrf->vrf;
+ if (vrf) {
+ vrf->info = NULL;
+ svrf->vrf = NULL;
+ }
+
+ RB_REMOVE(svrf_name_head, &svrfs, svrf);
+
+ for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+ for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+ table = svrf->stable[afi][safi];
+ info = route_table_get_info(table);
+ route_table_finish(table);
+ XFREE(MTYPE_STATIC_RTABLE_INFO, info);
+ svrf->stable[afi][safi] = NULL;
+ }
+ }
+
+ XFREE(MTYPE_STATIC_RTABLE_INFO, svrf);
+}
+
static int static_vrf_new(struct vrf *vrf)
{
struct static_vrf *svrf;
- svrf = static_vrf_alloc();
- vrf->info = svrf;
- svrf->vrf = vrf;
+ svrf = static_vrf_lookup_by_name(vrf->name);
+ if (svrf) {
+ vrf->info = svrf;
+ svrf->vrf = vrf;
+ }
return 0;
}
static int static_vrf_enable(struct vrf *vrf)
{
static_zebra_vrf_register(vrf);
-
- static_fixup_vrf_ids(vrf->info);
-
+ static_fixup_vrf_ids(vrf);
return 0;
}
static int static_vrf_disable(struct vrf *vrf)
{
+ static_cleanup_vrf_ids(vrf);
static_zebra_vrf_unregister(vrf);
return 0;
}
static int static_vrf_delete(struct vrf *vrf)
{
- struct route_table *table;
struct static_vrf *svrf;
- safi_t safi;
- afi_t afi;
- void *info;
svrf = vrf->info;
- for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
- for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
- table = svrf->stable[afi][safi];
- info = route_table_get_info(table);
- route_table_finish(table);
- XFREE(MTYPE_STATIC_RTABLE_INFO, info);
- svrf->stable[afi][safi] = NULL;
- }
+ if (svrf) {
+ svrf->vrf = NULL;
+ vrf->info = NULL;
}
- XFREE(MTYPE_STATIC_RTABLE_INFO, svrf);
+
return 0;
}
return svrf->stable[afi][safi];
}
-struct static_vrf *static_vrf_lookup_by_name(const char *name)
-{
- struct vrf *vrf;
-
- if (!name)
- name = VRF_DEFAULT_NAME;
-
- vrf = vrf_lookup_by_name(name);
- if (vrf)
- return ((struct static_vrf *)vrf->info);
-
- return NULL;
-}
-
void static_vrf_init(void)
{
vrf_init(static_vrf_new, static_vrf_enable, static_vrf_disable,
void static_vrf_terminate(void)
{
+ struct static_vrf *svrf, *svrf_next;
+
+ RB_FOREACH_SAFE (svrf, svrf_name_head, &svrfs, svrf_next)
+ static_vrf_free(svrf);
+
vrf_terminate();
}
#ifndef __STATIC_VRF_H__
#define __STATIC_VRF_H__
+#include "openbsd-tree.h"
+
#ifdef __cplusplus
extern "C" {
#endif
struct static_vrf {
+ RB_ENTRY(static_vrf) entry;
+
+ char name[VRF_NAMSIZ + 1];
struct vrf *vrf;
struct route_table *stable[AFI_MAX][SAFI_MAX];
};
+RB_HEAD(svrf_name_head, static_vrf);
+RB_PROTOTYPE(svrf_name_head, static_vrf, entry, svrf_name_compare)
+
+extern struct svrf_name_head svrfs;
+
+struct static_vrf *static_vrf_alloc(const char *name);
+void static_vrf_free(struct static_vrf *svrf);
struct stable_info {
struct static_vrf *svrf;
#define GET_STABLE_VRF_ID(info) info->svrf->vrf->vrf_id
-struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name);
-
void static_vrf_init(void);
struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
static int static_ifp_up(struct interface *ifp)
{
- /* Install any static reliant on this interface coming up */
- static_install_intf_nh(ifp);
static_ifindex_update(ifp, true);
return 0;
zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, true);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
- static_fixup_vrf_ids(vrf_info_lookup(VRF_DEFAULT));
+ static_fixup_vrf_ids(vrf_lookup_by_id(VRF_DEFAULT));
}
/* API to check whether the configured nexthop address is
struct zapi_route api;
uint32_t nh_num = 0;
+ if (!si->svrf->vrf)
+ return;
+
p = src_pp = NULL;
srcdest_rnode_prefixes(rn, &p, &src_pp);
hook_register(routing_conf_event,
routing_control_plane_protocols_name_validate);
-
- routing_control_plane_protocols_register_vrf_dependency();
+ hook_register(routing_create,
+ routing_control_plane_protocols_staticd_create);
+ hook_register(routing_destroy,
+ routing_control_plane_protocols_staticd_destroy);
// Add a route
vty = vty_new();