summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Westphal <renato@openbsd.org>2018-04-10 22:27:57 +0200
committerGitHub <noreply@github.com>2018-04-10 22:27:57 +0200
commit15da01e92d71047195a7387af3f693cb5ca3a970 (patch)
treeed43e9d42db2237b0566441c6a93f2dd688b631b
parentMerge pull request #1883 from LabNConsulting/working/master/community-documen... (diff)
parentzebra: Prevent crash in the off-chance we make a mistake (diff)
downloadfrr-15da01e92d71047195a7387af3f693cb5ca3a970.tar.xz
frr-15da01e92d71047195a7387af3f693cb5ca3a970.zip
Merge pull request #1973 from donaldsharp/static_nh_vrf
Static nh vrf
-rw-r--r--zebra/zebra_rib.c4
-rw-r--r--zebra/zebra_static.c249
-rw-r--r--zebra/zebra_static.h3
-rw-r--r--zebra/zebra_vrf.c44
-rw-r--r--zebra/zebra_vty.c16
5 files changed, 248 insertions, 68 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 48969e87f..6ad60a6ff 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2121,8 +2121,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
/* free RE and nexthops */
if (re->type == ZEBRA_ROUTE_STATIC)
- zebra_deregister_rnh_static_nexthops(re->vrf_id, re->ng.nexthop,
- rn);
+ zebra_deregister_rnh_static_nexthops(re->ng.nexthop->vrf_id,
+ re->ng.nexthop, rn);
nexthops_free(re->ng.nexthop);
XFREE(MTYPE_RE, re);
}
diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c
index 82b3ee974..914b049c0 100644
--- a/zebra/zebra_static.c
+++ b/zebra/zebra_static.c
@@ -46,12 +46,26 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
struct prefix nh_p;
struct nexthop *nexthop = NULL;
enum blackhole_type bh_type = 0;
+ struct vrf *nh_vrf;
/* Lookup table. */
table = zebra_vrf_table(afi, safi, si->vrf_id);
if (!table)
return;
+ /*
+ * If a specific vrf is coming up and the nexthop vrf we are
+ * looking at using hasn't been brought up yet, just don't
+ * install the static route yet.
+ * When the nexthop vrf comes up we will get another call
+ * back to do the right thing. I'm putting this check
+ * here because we are calling static_install_route a bunch
+ * from a bunch of different callpaths.
+ */
+ nh_vrf = vrf_lookup_by_id(si->nh_vrf_id);
+ if (!nh_vrf)
+ return;
+
memset(&nh_p, 0, sizeof(nh_p));
if (si->type == STATIC_BLACKHOLE) {
switch (si->bh_type) {
@@ -369,7 +383,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
nh_p.u.prefix6 = nexthop->gate.ipv6;
}
route_entry_nexthop_delete(re, nexthop);
- zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn);
+ zebra_deregister_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
nexthop_free(nexthop);
}
/* Unlock node. */
@@ -442,6 +456,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
si->tag = tag;
si->vrf_id = zvrf_id(zvrf);
si->nh_vrf_id = zvrf_id(nh_zvrf);
+ strcpy(si->nh_vrfname, nh_zvrf->vrf->name);
if (ifname)
strlcpy(si->ifname, ifname, sizeof(si->ifname));
@@ -573,33 +588,233 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
safi_t safi)
{
struct route_table *stable;
- struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
struct route_node *rn;
struct static_route *si;
struct prefix *p, *src_pp;
struct prefix_ipv6 *src_p;
+ struct vrf *vrf;
- stable = zebra_vrf_static_table(afi, safi, zvrf);
- if (!stable)
- return;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf->info;
- for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
- srcdest_rnode_prefixes(rn, &p, &src_pp);
- src_p = (struct prefix_ipv6 *)src_pp;
+ stable = zebra_vrf_static_table(afi, safi, zvrf);
+ if (!stable)
+ continue;
+
+ for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
+ srcdest_rnode_prefixes(rn, &p, &src_pp);
+ src_p = (struct prefix_ipv6 *)src_pp;
+ for (si = rn->info; si; si = si->next) {
+ if (!si->ifname[0])
+ continue;
+ if (up) {
+ if (strcmp(si->ifname, ifp->name))
+ continue;
+ si->ifindex = ifp->ifindex;
+ static_install_route(afi, safi, p, src_p, si);
+ } else {
+ if (si->ifindex != ifp->ifindex)
+ continue;
+ static_uninstall_route(afi, safi, p, src_p, si);
+ si->ifindex = IFINDEX_INTERNAL;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This function looks at a zvrf's stable and notices if any of the
+ * nexthops we are using are part of the vrf coming up.
+ * If we are using them then cleanup the nexthop vrf id
+ * to be the new value and then re-installs them
+ *
+ *
+ * stable -> The table we are looking at.
+ * zvrf -> The newly changed vrf.
+ * afi -> The afi to look at
+ * safi -> the safi to look at
+ */
+static void static_fixup_vrf(struct zebra_vrf *zvrf,
+ struct route_table *stable, afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+ struct interface *ifp;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
for (si = rn->info; si; si = si->next) {
- if (!si->ifname[0])
+ if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0)
continue;
- if (up) {
- if (strcmp(si->ifname, ifp->name))
+
+ si->nh_vrf_id = zvrf->vrf->vrf_id;
+ if (si->ifindex) {
+ ifp = if_lookup_by_name(si->ifname,
+ si->nh_vrf_id);
+ if (ifp)
+ si->ifindex = ifp->ifindex;
+ else
continue;
- si->ifindex = ifp->ifindex;
- static_install_route(afi, safi, p, src_p, si);
- } else {
- if (si->ifindex != ifp->ifindex)
+ }
+ static_install_route(afi, safi, &rn->p, NULL, si);
+ }
+ }
+}
+
+/*
+ * This function enables static routes in a zvrf as it
+ * is coming up. It sets the new vrf_id as appropriate.
+ *
+ * zvrf -> The zvrf that is being brought up and enabled by the kernel
+ * stable -> The stable we are looking at.
+ * afi -> the afi in question
+ * safi -> the safi in question
+ */
+static void static_enable_vrf(struct zebra_vrf *zvrf,
+ struct route_table *stable,
+ afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+ struct interface *ifp;
+ struct vrf *vrf = zvrf->vrf;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ si->vrf_id = vrf->vrf_id;
+ if (si->ifindex) {
+ ifp = if_lookup_by_name(si->ifname,
+ si->nh_vrf_id);
+ if (ifp)
+ si->ifindex = ifp->ifindex;
+ else
+ continue;
+ }
+ static_install_route(afi, safi, &rn->p, NULL, si);
+ }
+ }
+}
+
+/*
+ * When a vrf is being enabled by the kernel, go through all the
+ * static routes in the system that use this vrf (both nexthops vrfs
+ * and the routes vrf )
+ *
+ * enable_zvrf -> the vrf being enabled
+ */
+void static_fixup_vrf_ids(struct zebra_vrf *enable_zvrf)
+{
+ struct route_table *stable;
+ struct vrf *vrf;
+ afi_t afi;
+ safi_t safi;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf->info;
+ /* Install any static routes configured for this VRF. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ stable = zvrf->stable[afi][safi];
+ if (!stable)
+ continue;
+
+ static_fixup_vrf(enable_zvrf, stable,
+ afi, safi);
+
+ if (enable_zvrf == zvrf)
+ static_enable_vrf(zvrf, stable,
+ afi, safi);
+ }
+ }
+ }
+}
+
+/*
+ * Look at the specified stable and if any of the routes in
+ * this table are using the zvrf as the nexthop, uninstall
+ * those routes.
+ *
+ * zvrf -> the vrf being disabled
+ * stable -> the table we need to look at.
+ * afi -> the afi in question
+ * safi -> the safi in question
+ */
+static void static_cleanup_vrf(struct zebra_vrf *zvrf,
+ struct route_table *stable,
+ afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0)
+ continue;
+
+ static_uninstall_route(afi, safi, &rn->p, NULL, si);
+ }
+ }
+}
+
+/*
+ * Look at all static routes in this table and uninstall
+ * them.
+ *
+ * stable -> The table to uninstall from
+ * afi -> The afi in question
+ * safi -> the safi in question
+ */
+static void static_disable_vrf(struct route_table *stable,
+ afi_t afi, safi_t safi)
+{
+ struct route_node *rn;
+ struct static_route *si;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ for (si = rn->info; si; si = si->next) {
+ static_uninstall_route(afi, safi, &rn->p, NULL, si);
+ }
+ }
+}
+
+/*
+ * When the disable_zvrf is shutdown by the kernel, we call
+ * this function and it cleans up all static routes using
+ * this vrf as a nexthop as well as all static routes
+ * in it's stables.
+ *
+ * disable_zvrf - The vrf being disabled
+ */
+void static_cleanup_vrf_ids(struct zebra_vrf *disable_zvrf)
+{
+ struct vrf *vrf;
+ afi_t afi;
+ safi_t safi;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf->info;
+
+ /* Uninstall any static routes configured for this VRF. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ struct route_table *stable;
+
+ stable = zvrf->stable[afi][safi];
+ if (!stable)
continue;
- static_uninstall_route(afi, safi, p, src_p, si);
- si->ifindex = IFINDEX_INTERNAL;
+
+ static_cleanup_vrf(disable_zvrf, stable,
+ afi, safi);
+
+ if (disable_zvrf == zvrf)
+ static_disable_vrf(stable, afi, safi);
}
}
}
diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h
index a12e465e7..341905f42 100644
--- a/zebra/zebra_static.h
+++ b/zebra/zebra_static.h
@@ -55,6 +55,7 @@ struct static_route {
/* VRF identifier. */
vrf_id_t vrf_id;
vrf_id_t nh_vrf_id;
+ char nh_vrfname[VRF_NAMSIZ + 1];
/* Administrative distance. */
uint8_t distance;
@@ -102,4 +103,6 @@ extern int static_delete_route(afi_t, safi_t safi, uint8_t type,
extern void static_ifindex_update(struct interface *ifp, bool up);
+extern void static_cleanup_vrf_ids(struct zebra_vrf *zvrf);
+extern void static_fixup_vrf_ids(struct zebra_vrf *zvrf);
#endif
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index fe1b10057..76dc5657d 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -102,11 +102,7 @@ static int zebra_vrf_new(struct vrf *vrf)
static int zebra_vrf_enable(struct vrf *vrf)
{
struct zebra_vrf *zvrf = vrf->info;
- struct route_table *stable;
- struct route_node *rn;
- struct static_route *si;
struct route_table *table;
- struct interface *ifp;
afi_t afi;
safi_t safi;
@@ -138,29 +134,7 @@ static int zebra_vrf_enable(struct vrf *vrf)
zvrf->import_check_table[afi] = table;
}
- /* Install any static routes configured for this VRF. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- stable = zvrf->stable[afi][safi];
- if (!stable)
- continue;
-
- for (rn = route_top(stable); rn; rn = route_next(rn))
- for (si = rn->info; si; si = si->next) {
- si->vrf_id = vrf->vrf_id;
- if (si->ifindex) {
- ifp = if_lookup_by_name(
- si->ifname, si->vrf_id);
- if (ifp)
- si->ifindex =
- ifp->ifindex;
- else
- continue;
- }
- static_install_route(afi, safi, &rn->p,
- NULL, si);
- }
- }
+ static_fixup_vrf_ids(zvrf);
/*
* We may have static routes that are now possible to
@@ -178,9 +152,6 @@ static int zebra_vrf_enable(struct vrf *vrf)
static int zebra_vrf_disable(struct vrf *vrf)
{
struct zebra_vrf *zvrf = vrf->info;
- struct route_table *stable;
- struct route_node *rn;
- struct static_route *si;
struct route_table *table;
struct interface *ifp;
afi_t afi;
@@ -192,18 +163,7 @@ static int zebra_vrf_disable(struct vrf *vrf)
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
zvrf_id(zvrf));
- /* Uninstall any static routes configured for this VRF. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- stable = zvrf->stable[afi][safi];
- if (!stable)
- continue;
-
- for (rn = route_top(stable); rn; rn = route_next(rn))
- for (si = rn->info; si; si = si->next)
- static_uninstall_route(
- afi, safi, &rn->p, NULL, si);
- }
+ static_cleanup_vrf_ids(zvrf);
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index a79e27fea..84fc76d7f 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1107,7 +1107,10 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
struct vrf *vrf =
vrf_lookup_by_id(nexthop->vrf_id);
- vty_out(vty, "(vrf %s)", vrf->name);
+ if (vrf)
+ vty_out(vty, "(vrf %s)", vrf->name);
+ else
+ vty_out(vty, "(vrf UKNOWN)");
}
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
@@ -1467,7 +1470,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
if (nexthop->vrf_id != re->vrf_id) {
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
- vty_out(vty, "(vrf %s)", vrf->name);
+ if (vrf)
+ vty_out(vty, "(vrf %s)", vrf->name);
+ else
+ vty_out(vty, "(vrf UKNOWN)");
}
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -2304,11 +2310,7 @@ int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi,
sizeof buf, 0));
if (si->nh_vrf_id != si->vrf_id) {
- struct vrf *vrf;
-
- vrf = vrf_lookup_by_id(si->nh_vrf_id);
- vty_out(vty, " nexthop-vrf %s",
- (vrf) ? vrf->name : "Unknown");
+ vty_out(vty, " nexthop-vrf %s", si->nh_vrfname);
}
vty_out(vty, "\n");