summaryrefslogtreecommitdiff
path: root/pbrd/pbr_nht.c
diff options
context:
space:
mode:
Diffstat (limited to 'pbrd/pbr_nht.c')
-rw-r--r--pbrd/pbr_nht.c61
1 files changed, 59 insertions, 2 deletions
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index ce7780ed49..dbe5de724c 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -718,9 +718,57 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
struct pbr_nht_individual *pnhi)
{
bool is_valid = pnhc->valid;
+ bool all_done = false;
- if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */
+ /*
+ * If we have an interface down event, let's note that
+ * it is happening and find all the nexthops that depend
+ * on that interface. As that if we have an interface
+ * flapping fast enough it means that zebra might turn
+ * those nexthop tracking events into a no-update
+ * So let's search and do the right thing on the
+ * interface event.
+ */
+ if (!pnhi->nhr && pnhi->ifp) {
+ struct connected *connected;
+ struct listnode *node;
+ struct prefix p;
+
+ switch (pnhc->nexthop.type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ all_done = true;
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ is_valid = if_is_up(pnhi->ifp);
+ all_done = true;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = pnhc->nexthop.gate.ipv4;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_BITLEN;
+ memcpy(&p.u.prefix6, &pnhc->nexthop.gate.ipv6,
+ sizeof(struct in6_addr));
+ break;
+ }
+
+ /* Early exit in a couple of cases. */
+ if (all_done)
+ goto done;
+
+ FOR_ALL_INTERFACES_ADDRESSES (pnhi->ifp, connected, node) {
+ if (prefix_match(connected->address, &p)) {
+ is_valid = if_is_up(pnhi->ifp);
+ break;
+ }
+ }
goto done;
+ }
switch (pnhi->nhr->prefix.family) {
case AF_INET:
@@ -983,7 +1031,6 @@ static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data)
struct pbr_vrf *pbr_vrf = data;
struct pbr_nht_individual pnhi = {};
- zlog_debug("pnhgc iterating");
hash_iterate(pnhgc->nhh, pbr_nht_clear_looked_at, NULL);
memset(&pnhi, 0, sizeof(pnhi));
pnhi.pbr_vrf = pbr_vrf;
@@ -1097,6 +1144,7 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
{
struct pbr_nexthop_group_cache *pnhgc = b->data;
struct pbr_nht_individual pnhi = {};
+ struct nexthop_group nhg = {};
bool old_valid;
old_valid = pnhgc->valid;
@@ -1111,6 +1159,15 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
*/
pnhgc->valid = pnhi.valid;
+ pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
+
+ if (pnhgc->valid)
+ pbr_nht_install_nexthop_group(pnhgc, nhg);
+ else
+ pbr_nht_uninstall_nexthop_group(pnhgc, nhg, 0);
+
+ nexthops_free(nhg.nexthop);
+
if (old_valid != pnhgc->valid)
pbr_map_check_nh_group_change(pnhgc->name);
}