DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
name);
- pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(name);
}
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(nhgc->name);
- if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
+ if (nhop->type == NEXTHOP_TYPE_IFINDEX
+ || (nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ && IN6_IS_ADDR_LINKLOCAL(&nhop->gate.ipv6))) {
struct interface *ifp;
ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
struct pbr_nexthop_group_cache find;
struct pbr_nexthop_cache *pnhc;
struct pbr_nexthop_cache lup;
- struct pbr_map *pbrm = pbrms->parent;
- struct listnode *node;
- struct pbr_map_interface *pmi;
struct nexthop *nh;
enum nexthop_types_t nh_type = 0;
- if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
- for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
- pbr_send_pbr_map(pbrms, pmi, false);
- }
-
- pbrm->valid = false;
- pbrms->nhs_installed = false;
- pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
+ pbr_map_delete_nexthops(pbrms);
memset(&find, 0, sizeof(find));
snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);
hash_release(pbr_nhg_hash, pnhgc);
- _nexthop_del(pbrms->nhg, nh);
- nexthop_free(nh);
nexthop_group_delete(&pbrms->nhg);
XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
}
if (pbrms->nhgrp_name
&& strmatch(pbrms->nhgrp_name, name)) {
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
- nexthop_group_delete(&pbrms->nhg);
pbrms->nhg = NULL;
pbrms->internal_nhg_name = NULL;
pbrm->valid = false;
uint32_t valid;
};
-static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
- void *data)
+static bool
+pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
+ const struct pbr_nht_individual *pnhi)
{
- struct pbr_nexthop_cache *pnhc = b->data;
- struct pbr_nht_individual *pnhi = data;
- char buf[PREFIX_STRLEN];
- bool old_valid;
+ bool is_valid = pnhc->valid;
- old_valid = pnhc->valid;
+ if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */
+ goto done;
switch (pnhi->nhr->prefix.family) {
case AF_INET:
if (pnhc->nexthop->gate.ipv4.s_addr
- == pnhi->nhr->prefix.u.prefix4.s_addr)
- pnhc->valid = !!pnhi->nhr->nexthop_num;
+ != pnhi->nhr->prefix.u.prefix4.s_addr)
+ goto done; /* Unrelated change */
break;
case AF_INET6:
if (memcmp(&pnhc->nexthop->gate.ipv6,
&pnhi->nhr->prefix.u.prefix6, 16)
- == 0)
- pnhc->valid = !!pnhi->nhr->nexthop_num;
+ != 0)
+ goto done; /* Unrelated change */
break;
}
+ if (!pnhi->nhr->nexthop_num) {
+ is_valid = false;
+ goto done;
+ }
+
+ if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+ || pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
+
+ /* GATEWAY_IFINDEX type shouldn't resolve to group */
+ if (pnhi->nhr->nexthop_num > 1) {
+ is_valid = false;
+ goto done;
+ }
+
+ /* If whatever we resolved to wasn't on the interface we
+ * specified. (i.e. not a connected route), its invalid.
+ */
+ if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop->ifindex) {
+ is_valid = false;
+ goto done;
+ }
+ }
+
+ is_valid = true;
+
+done:
+ pnhc->valid = is_valid;
+
+ return pnhc->valid;
+}
+
+static bool pbr_nht_individual_nexthop_interface_update(
+ struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi)
+{
+ bool is_valid = pnhc->valid;
+
+ if (!pnhi->ifp) /* It doesn't care about non-interface updates */
+ goto done;
+
+ if (pnhc->nexthop->ifindex
+ != pnhi->ifp->ifindex) /* Un-related interface */
+ goto done;
+
+ is_valid = !!if_is_up(pnhi->ifp);
+
+done:
+ pnhc->valid = is_valid;
+
+ return pnhc->valid;
+}
+
+/* Given this update either from interface or nexthop tracking, re-validate this
+ * nexthop.
+ *
+ * If the update is un-related, the subroutines shoud just return their cached
+ * valid state.
+ */
+static void
+pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
+ const struct pbr_nht_individual *pnhi)
+{
+ assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */
+
+ switch (pnhc->nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (IN6_IS_ADDR_LINKLOCAL(&pnhc->nexthop->gate.ipv6)) {
+ pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
+ break;
+ }
+ /* Intentional fall thru */
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ pbr_nht_individual_nexthop_gw_update(pnhc, pnhi);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ pnhc->valid = true;
+ break;
+ }
+}
+
+static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
+ void *data)
+{
+ struct pbr_nexthop_cache *pnhc = b->data;
+ struct pbr_nht_individual *pnhi = data;
+ char buf[PREFIX_STRLEN];
+ bool old_valid;
+
+ old_valid = pnhc->valid;
+
+ pbr_nht_individual_nexthop_update(pnhc, pnhi);
+
DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
pnhc->valid);
static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
{
struct pbr_nexthop_group_cache *pnhgc = b->data;
- struct pbr_nht_individual pnhi;
+ struct pbr_nht_individual pnhi = {};
struct nexthop_group nhg = {};
bool old_valid;
old_valid = pnhc->valid;
- if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
- && pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
- pnhc->valid = !!if_is_up(pnhi->ifp);
+ pbr_nht_individual_nexthop_update(pnhc, pnhi);
DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
old_valid, pnhc->valid);
void *data)
{
struct pbr_nexthop_group_cache *pnhgc = b->data;
- struct pbr_nht_individual pnhi;
+ struct pbr_nht_individual pnhi = {};
bool old_valid;
old_valid = pnhgc->valid;