return 1;
}
-/* Add nexthop to the end of a rib node's nexthop list */
-void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop)
-{
- _nexthop_group_add_sorted(re->ng, nexthop);
-}
-
-
/**
* copy_nexthop - copy a nexthop to the rib structure.
*/
void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh)
{
- assert(!re->ng->nexthop);
- copy_nexthops(&re->ng->nexthop, nh, NULL);
-}
-
-/* Delete specified nexthop from the list. */
-void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop)
-{
- if (nexthop->next)
- nexthop->next->prev = nexthop->prev;
- if (nexthop->prev)
- nexthop->prev->next = nexthop->next;
- else
- re->ng->nexthop = nexthop->next;
+ assert(!re->nhe->nhg->nexthop);
+ copy_nexthops(&re->nhe->nhg->nexthop, nh, NULL);
}
-
-struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
- ifindex_t ifindex,
- vrf_id_t nh_vrf_id)
+static void route_entry_attach_ref(struct route_entry *re,
+ struct nhg_hash_entry *new)
{
- struct nexthop *nexthop;
-
- nexthop = nexthop_new();
- nexthop->type = NEXTHOP_TYPE_IFINDEX;
- nexthop->ifindex = ifindex;
- nexthop->vrf_id = nh_vrf_id;
-
- route_entry_nexthop_add(re, nexthop);
-
- return nexthop;
-}
-
-struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re,
- struct in_addr *ipv4,
- struct in_addr *src,
- vrf_id_t nh_vrf_id)
-{
- struct nexthop *nexthop;
-
- nexthop = nexthop_new();
- nexthop->type = NEXTHOP_TYPE_IPV4;
- nexthop->vrf_id = nh_vrf_id;
- nexthop->gate.ipv4 = *ipv4;
- if (src)
- nexthop->src.ipv4 = *src;
-
- route_entry_nexthop_add(re, nexthop);
+ re->nhe = new;
+ re->nhe_id = new->id;
- return nexthop;
+ zebra_nhg_increment_ref(new);
}
-struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
- struct in_addr *ipv4,
- struct in_addr *src,
- ifindex_t ifindex,
- vrf_id_t nh_vrf_id)
+int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
{
- struct nexthop *nexthop;
- struct interface *ifp;
-
- nexthop = nexthop_new();
- nexthop->vrf_id = nh_vrf_id;
- nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
- nexthop->gate.ipv4 = *ipv4;
- if (src)
- nexthop->src.ipv4 = *src;
- nexthop->ifindex = ifindex;
- ifp = if_lookup_by_index(nexthop->ifindex, nh_vrf_id);
- /*Pending: need to think if null ifp here is ok during bootup?
- There was a crash because ifp here was coming to be NULL */
- if (ifp)
- if (connected_is_unnumbered(ifp))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
-
- route_entry_nexthop_add(re, nexthop);
-
- return nexthop;
-}
-
-struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re,
- struct in6_addr *ipv6,
- vrf_id_t nh_vrf_id)
-{
- struct nexthop *nexthop;
-
- nexthop = nexthop_new();
- nexthop->vrf_id = nh_vrf_id;
- nexthop->type = NEXTHOP_TYPE_IPV6;
- nexthop->gate.ipv6 = *ipv6;
-
- route_entry_nexthop_add(re, nexthop);
-
- return nexthop;
-}
-
-struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
- struct in6_addr *ipv6,
- ifindex_t ifindex,
- vrf_id_t nh_vrf_id)
-{
- struct nexthop *nexthop;
-
- nexthop = nexthop_new();
- nexthop->vrf_id = nh_vrf_id;
- nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
- nexthop->gate.ipv6 = *ipv6;
- nexthop->ifindex = ifindex;
-
- route_entry_nexthop_add(re, nexthop);
+ struct nhg_hash_entry *old = NULL;
+ int ret = 0;
- return nexthop;
-}
+ if (new == NULL) {
+ re->nhe->nhg = NULL;
+ goto done;
+ }
-struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re,
- enum blackhole_type bh_type)
-{
- struct nexthop *nexthop;
+ if (re->nhe_id != new->id) {
+ old = zebra_nhg_lookup_id(re->nhe_id);
- nexthop = nexthop_new();
- nexthop->vrf_id = VRF_DEFAULT;
- nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
- nexthop->bh_type = bh_type;
+ route_entry_attach_ref(re, new);
- route_entry_nexthop_add(re, nexthop);
+ if (old)
+ zebra_nhg_decrement_ref(old);
+ } else if (!re->nhe)
+ /* This is the first time it's being attached */
+ route_entry_attach_ref(re, new);
- return nexthop;
+done:
+ return ret;
}
struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
if (re->type != ZEBRA_ROUTE_BGP)
return 0;
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop))
if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
return 0;
srcdest_rnode_prefixes(rn, &p, &src_p);
if (info->safi != SAFI_UNICAST) {
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
return;
}
if (info->safi != SAFI_UNICAST) {
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
return;
}
re->fib_ng.nexthop = NULL;
}
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
/* Update real nexthop. This may actually determine if nexthop is active
* or not. */
- if (!nexthop_group_active_nexthop_num(new->ng)) {
+ if (!nexthop_group_active_nexthop_num(new->nhe->nhg)) {
UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
return;
}
/* Update the nexthop; we could determine here that nexthop is
* inactive. */
- if (nexthop_group_active_nexthop_num(new->ng))
+ if (nexthop_group_active_nexthop_num(new->nhe->nhg))
nh_active = 1;
/* If nexthop is active, install the selected route, if
/* both are connected. are either loop or vrf? */
struct nexthop *nexthop = NULL;
- for (ALL_NEXTHOPS_PTR(alternate->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(alternate->nhe->nhg, nexthop)) {
struct interface *ifp = if_lookup_by_index(
nexthop->ifindex, alternate->vrf_id);
return alternate;
}
- for (ALL_NEXTHOPS_PTR(current->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(current->nhe->nhg, nexthop)) {
struct interface *ifp = if_lookup_by_index(
nexthop->ifindex, current->vrf_id);
}
/* Infinite distance. */
- if (re->distance == DISTANCE_INFINITY) {
+ if (re->distance == DISTANCE_INFINITY &&
+ re->type != ZEBRA_ROUTE_KERNEL) {
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
continue;
}
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
- for (ALL_NEXTHOPS_PTR(re->ng, nhop)) {
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nhop)) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
ctx_nexthop = dplane_ctx_get_ng(ctx)->nexthop;
+ /* Nothing installed - we can skip some of the checking/comparison
+ * of nexthops.
+ */
+ if (ctx_nexthop == NULL) {
+ changed_p = true;
+ goto no_nexthops;
+ }
+
/* Get the first `installed` one to check against.
* If the dataplane doesn't set these to be what was actually installed,
- * it will just be whatever was in re->ng?
+ * it will just be whatever was in re->nhe->nhg?
*/
if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
|| !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE))
ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop);
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
goto done;
}
+no_nexthops:
+
/* FIB nexthop set differs from the RIB set:
* create a fib-specific nexthop-group
*/
/* Ensure we clear the QUEUED flag */
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
- /* Is this a notification that ... matters? We only really care about
- * the route that is currently selected for installation.
+ /* Is this a notification that ... matters? We mostly care about
+ * the route that is currently selected for installation; we may also
+ * get an un-install notification, and handle that too.
*/
if (re != dest->selected_fib) {
- /* TODO -- don't skip processing entirely? We might like to
- * at least report on the event.
+ /*
+ * If we need to, clean up after a delete that was part of
+ * an update operation.
*/
- if (debug_p)
- zlog_debug("%u:%s dplane notif, but type %s not selected_fib",
- dplane_ctx_get_vrf(ctx), dest_str,
- zebra_route_string(
- dplane_ctx_get_type(ctx)));
+ end_count = 0;
+ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ end_count++;
+ }
+
+ /* If no nexthops or none installed, ensure that this re
+ * gets its 'installed' flag cleared.
+ */
+ if (end_count == 0) {
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+ UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ if (debug_p)
+ zlog_debug("%u:%s dplane notif, uninstalled type %s route",
+ dplane_ctx_get_vrf(ctx), dest_str,
+ zebra_route_string(
+ dplane_ctx_get_type(ctx)));
+ } else {
+ /* At least report on the event. */
+ if (debug_p)
+ zlog_debug("%u:%s dplane notif, but type %s not selected_fib",
+ dplane_ctx_get_vrf(ctx), dest_str,
+ zebra_route_string(
+ dplane_ctx_get_type(ctx)));
+ }
goto done;
}
* and then again if there's been a change.
*/
start_count = 0;
- for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- start_count++;
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
+ for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ start_count++;
+ }
}
/* Update zebra's nexthop FIB flags based on the context struct's
if (!fib_changed) {
if (debug_p)
- zlog_debug("%u:%s No change from dplane notification",
+ zlog_debug("%u:%s dplane notification: rib_update returns FALSE",
dplane_ctx_get_vrf(ctx), dest_str);
-
- goto done;
}
/*
/* Redistribute, lsp, and nht update */
redistribute_update(dest_pfx, src_pfx, re, NULL);
- zebra_rib_evaluate_rn_nexthops(
- rn, zebra_router_get_next_sequence());
-
- zebra_rib_evaluate_mpls(rn);
-
} else if (start_count > 0 && end_count == 0) {
if (debug_p)
zlog_debug("%u:%s un-installed transition from dplane notification",
/* Redistribute, lsp, and nht update */
redistribute_delete(dest_pfx, src_pfx, re, NULL);
+ }
- zebra_rib_evaluate_rn_nexthops(
- rn, zebra_router_get_next_sequence());
+ /* Make any changes visible for lsp and nexthop-tracking processing */
+ zebra_rib_evaluate_rn_nexthops(
+ rn, zebra_router_get_next_sequence());
- zebra_rib_evaluate_mpls(rn);
- }
+ zebra_rib_evaluate_mpls(rn);
done:
if (rn)
nhe = zebra_nhg_lookup_id(re->nhe_id);
if (nhe)
zebra_nhg_decrement_ref(nhe);
- } else if (re->ng)
- nexthop_group_delete(&re->ng);
+ } else if (re->nhe->nhg)
+ nexthop_group_delete(&re->nhe->nhg);
nexthops_free(re->fib_ng.nexthop);
"%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
straddr, re->metric, re->mtu, re->distance, re->flags, re->status);
zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
- nexthop_group_nexthop_num(re->ng),
- nexthop_group_active_nexthop_num(re->ng));
+ nexthop_group_nexthop_num(re->nhe->nhg),
+ nexthop_group_active_nexthop_num(re->nhe->nhg));
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) {
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
}
int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_ipv6 *src_p, struct route_entry *re)
+ struct prefix_ipv6 *src_p, struct route_entry *re,
+ struct nexthop_group *ng)
{
struct nhg_hash_entry *nhe = NULL;
struct route_table *table;
table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id,
re->table);
if (!table) {
- if (re->ng)
- nexthop_group_delete(&re->ng);
+ if (ng)
+ nexthop_group_delete(&ng);
XFREE(MTYPE_RE, re);
return 0;
}
return -1;
}
} else {
- nhe = zebra_nhg_rib_find(0, re->ng, afi);
+ nhe = zebra_nhg_rib_find(0, ng, afi);
/*
* The nexthops got copied over into an nhe,
* so free them now.
*/
- nexthop_group_delete(&re->ng);
+ nexthop_group_delete(&ng);
if (!nhe) {
char buf[PREFIX_STRLEN] = "";
* level protocols, as the refcnt might be wrong, since it checks
* if old_id != new_id.
*/
- zebra_nhg_re_update_ref(re, nhe);
+ route_entry_update_nhe(re, nhe);
/* Make it sure prefixlen is applied to the prefix. */
apply_mask(p);
if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric)
continue;
- if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng->nexthop)
+ if (re->type == ZEBRA_ROUTE_CONNECT &&
+ (rtnh = re->nhe->nhg->nexthop)
&& rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) {
if (rtnh->ifindex != nh->ifindex)
continue;
same = re;
break;
}
- for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) {
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, rtnh)) {
/*
* No guarantee all kernel send nh with labels
* on delete.
if (allow_delete) {
UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED);
/* Unset flags. */
- for (rtnh = fib->ng->nexthop; rtnh;
+ for (rtnh = fib->nhe->nhg->nexthop; rtnh;
rtnh = rtnh->next)
UNSET_FLAG(rtnh->flags,
NEXTHOP_FLAG_FIB);
if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
struct nexthop *tmp_nh;
- for (ALL_NEXTHOPS_PTR(re->ng, tmp_nh)) {
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, tmp_nh)) {
struct ipaddr vtep_ip;
memset(&vtep_ip, 0, sizeof(struct ipaddr));
{
struct route_entry *re = NULL;
struct nexthop *nexthop = NULL;
+ struct nexthop_group *ng = NULL;
/* Allocate new route_entry structure. */
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
re->tag = tag;
re->nhe_id = nhe_id;
+ /* If the owner of the route supplies a shared nexthop-group id,
+ * we'll use that. Otherwise, pass the nexthop along directly.
+ */
if (!nhe_id) {
- re->ng = nexthop_group_new();
+ ng = nexthop_group_new();
/* Add nexthop. */
nexthop = nexthop_new();
*nexthop = *nh;
- route_entry_nexthop_add(re, nexthop);
+ nexthop_group_add_sorted(ng, nexthop);
}
- return rib_add_multipath(afi, safi, p, src_p, re);
+ return rib_add_multipath(afi, safi, p, src_p, re, ng);
}
static const char *rib_update_event2str(rib_update_event_t event)
* this decision needs to be revisited
*/
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
- for (ALL_NEXTHOPS_PTR(re->ng, nexthop))
+ for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
rib_uninstall_kernel(rn, re);
* Array that helps us go over all AFI/SAFI combinations via one
* index.
*/
- static struct {
+ static const struct {
afi_t afi;
safi_t safi;
} afi_safis[] = {