Before, only one level of recursive resolution was supported.
Signed-off-by: ßingen <bingen@voltanet.io>
}
void
-copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
+copy_nexthops (struct nexthop **tnh, struct nexthop *nh, struct nexthop *rparent)
{
struct nexthop *nexthop;
struct nexthop *nh1;
memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
if (nh->nh_label)
nexthop_add_labels (nexthop, nh->nh_label_type,
- nh->nh_label->num_labels, &nh->nh_label->label[0]);
+ nh->nh_label->num_labels, &nh->nh_label->label[0]);
+ nexthop->rparent = rparent;
nexthop_add(tnh, nexthop);
if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
- copy_nexthops(&nexthop->resolved, nh1->resolved);
+ copy_nexthops(&nexthop->resolved, nh1->resolved, nexthop);
}
}
* If the nexthop struct needs to be resolved recursively,
* NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
* obtained by recursive resolution will be added to `resolved'.
- * Only one level of recursive resolution is currently supported. */
+ */
struct nexthop *resolved;
+ /* Recursive parent */
+ struct nexthop *rparent;
/* Type of label(s), if any */
enum lsp_types_t nh_label_type;
struct nexthop *nexthop_new (void);
void nexthop_add (struct nexthop **target, struct nexthop *nexthop);
-void copy_nexthops (struct nexthop **tnh, struct nexthop *nh);
+void copy_nexthops (struct nexthop **tnh, struct nexthop *nh, struct nexthop *rparent);
void nexthop_free (struct nexthop *nexthop);
void nexthops_free (struct nexthop *nexthop);
static void
nexthop_chain_verify_iter(struct nexthop_chain *nc)
{
- struct nexthop *nh, *tnh;
- int recursing;
+ struct nexthop *nh;
char *repr = NULL;
- for (ALL_NEXTHOPS_RO(nc->head, nh, tnh, recursing))
+ for (ALL_NEXTHOPS_RO(nc->head, nh))
{
- if (recursing)
+ if (nh->rparent)
str_appendf(&repr, " %p\n", nh);
else
str_appendf(&repr, "%p\n", nh);
* Iteration check: Check that the `nexthop' pointer is not NULL.
*
* Iteration step: This is the tricky part. Check if `nexthop' has
- * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' is in
- * the top level chain and has at least one nexthop attached to
- * `nexthop->resolved'. As we want to descend into `nexthop->resolved',
- * set `recursing' to 1 and set `nexthop' to `nexthop->resolved'.
- * `tnexthop' is left alone in that case so we can remember which nexthop
- * in the top level chain we are currently handling.
+ * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' has
+ * at least one nexthop attached to `nexthop->resolved'.
*
* If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its
- * current chain. If we are recursing, `nexthop' will be set to
- * `nexthop->next' and `tnexthop' will be left alone. If we are not
- * recursing, both `tnexthop' and `nexthop' will be set to `nexthop->next'
- * as we are progressing in the top level chain.
- * If we encounter `nexthop->next == NULL', we will clear the `recursing'
- * flag as we arived either at the end of the resolved chain or at the end
- * of the top level chain. In both cases, we set `tnexthop' and `nexthop'
- * to `tnexthop->next', progressing to the next position in the top-level
- * chain and possibly to its end marked by NULL.
+ * current chain. In case its current chain end is reached, it will try
+ * to get up to the previous recursion level and progress there. Whenever
+ * a step forward in a chain is done, recursion will be checked again.
+ * In a nustshell, it's equivalent to a pre-traversal order assuming that
+ * left branch is 'resolved' and right branch is 'next':
+ * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
*/
-#define ALL_NEXTHOPS_RO(head, nexthop, tnexthop, recursing) \
- (tnexthop) = (nexthop) = (head), (recursing) = 0; \
- (nexthop); \
- (nexthop) = CHECK_FLAG((nexthop)->flags, NEXTHOP_FLAG_RECURSIVE) \
- ? (((recursing) = 1), (nexthop)->resolved) \
- : ((nexthop)->next ? ((recursing) ? (nexthop)->next \
- : ((tnexthop) = (nexthop)->next)) \
- : (((recursing) = 0),((tnexthop) = (tnexthop)->next)))
+#define ALL_NEXTHOPS_RO(head, nexthop) \
+ (nexthop) = (head); \
+ (nexthop); \
+ (nexthop) = CHECK_FLAG((nexthop)->flags, NEXTHOP_FLAG_RECURSIVE) \
+ ? ((nexthop)->resolved) \
+ : ((nexthop)->next ? (nexthop)->next \
+ : ((nexthop)->rparent ? (nexthop)->rparent->next : NULL))
#if defined (HAVE_RTADV)
/* Structure which hold status of router advertisement. */
{
int bytelen;
struct sockaddr_nl snl;
- struct nexthop *nexthop = NULL, *tnexthop;
- int recursing;
+ struct nexthop *nexthop = NULL;
unsigned int nexthop_num;
int discard;
int family = PREFIX_FAMILY(p);
if (discard)
{
if (cmd == RTM_NEWROUTE)
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
/* We shouldn't encounter recursive nexthops on discard routes,
* but it is probably better to handle that case correctly anyway.
/* Count overall nexthops so we can decide whether to use singlepath
* or multipath case. */
nexthop_num = 0;
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
if (nexthop_num == 1 || multipath_num == 1)
{
nexthop_num = 0;
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
{
|| (cmd == RTM_DELROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
{
- routedesc = recursing ? "recursive, 1 hop" : "single hop";
+ routedesc = nexthop->rparent ? "recursive, 1 hop" : "single hop";
_netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
_netlink_route_build_singlepath(routedesc, bytelen,
rtnh = RTA_DATA (rta);
nexthop_num = 0;
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (nexthop_num >= multipath_num)
break;
|| (cmd == RTM_DELROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
{
- routedesc = recursing ? "recursive, multihop" : "multihop";
+ routedesc = nexthop->rparent ? "recursive, multihop" : "multihop";
nexthop_num++;
_netlink_route_debug(cmd, p, nexthop,
struct sockaddr_mpls smpls;
#endif
union sockunion *smplsp = NULL;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
int nexthop_num = 0;
ifindex_t ifindex = 0;
int gate = 0;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
/* Make gateway. */
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
{
struct sockaddr_in6 *mask;
struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
int nexthop_num = 0;
ifindex_t ifindex = 0;
int gate = 0;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
/* Make gateway. */
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
rib_dest_t *dest, struct route_entry *re)
{
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
int discard;
memset (ri, 0, sizeof (*ri));
if (discard)
return 1;
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (ri->num_nhs >= multipath_num)
break;
|| (cmd == RTM_DELROUTE
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
{
- netlink_route_info_add_nh (ri, nexthop, recursing);
+ netlink_route_info_add_nh (ri, nexthop, (nexthop->rparent ? 1 : 0));
}
}
if (nh->nh_label)
nexthop_add_labels (nexthop, nh->nh_label_type, nh->nh_label->num_labels,
&nh->nh_label->label[0]);
+ nexthop->rparent = NULL;
route_entry_nexthop_add(re, nexthop);
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
- copy_nexthops(&nexthop->resolved, nh->resolved);
+ copy_nexthops(&nexthop->resolved, nh->resolved, nexthop);
}
/* Delete specified nexthop from the list. */
resolved_hop->ifindex = newhop->ifindex;
}
+ resolved_hop->rparent = nexthop;
nexthop_add(&nexthop->resolved, resolved_hop);
}
struct route_node *rn;
struct route_entry *match;
int resolved;
- struct nexthop *newhop, *tnewhop;
- int recursing = 0;
+ struct nexthop *newhop;
struct interface *ifp;
if ((nexthop->type == NEXTHOP_TYPE_IPV4) || nexthop->type == NEXTHOP_TYPE_IPV6)
else if (CHECK_FLAG (re->flags, ZEBRA_FLAG_INTERNAL))
{
resolved = 0;
- for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop))
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
{
else if (re->type == ZEBRA_ROUTE_STATIC)
{
resolved = 0;
- for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop))
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
{
if (set)
struct route_table *table;
struct route_node *rn;
struct route_entry *match;
- struct nexthop *newhop, *tnewhop;
- int recursing;
+ struct nexthop *newhop;
/* Lookup table. */
table = zebra_vrf_table (afi, safi, vrf_id);
if (match->type != ZEBRA_ROUTE_CONNECT)
{
int found = 0;
- for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop))
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
{
found = 1;
struct route_table *table;
struct route_node *rn;
struct route_entry *match;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
/* Lookup table. */
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (match->type == ZEBRA_ROUTE_CONNECT)
return match;
-
- for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
+
+ for (ALL_NEXTHOPS_RO(match->nexthop, nexthop))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
return match;
struct route_table *table;
struct route_node *rn;
struct route_entry *match;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
int nexthops_active;
/* Lookup table. */
/* Ok, we have a cood candidate, let's check it's nexthop list... */
nexthops_active = 0;
- for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(match->nexthop, nexthop))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
nexthops_active = 1;
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
inet_ntop (AF_INET, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN);
zlog_debug ("%s: qgate == %s, %s == %s", __func__,
- qgate_buf, recursing ? "rgate" : "gate", gate_buf);
+ qgate_buf, nexthop->rparent ? "rgate" : "gate", gate_buf);
}
}
int
zebra_rib_labeled_unicast (struct route_entry *re)
{
- struct nexthop *nexthop = NULL, *tnexthop;
- int recursing;
+ struct nexthop *nexthop = NULL;
if (re->type != ZEBRA_ROUTE_BGP)
return 0;
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
return 0;
rib_install_kernel (struct route_node *rn, struct route_entry *re, struct route_entry *old)
{
int ret = 0;
- struct nexthop *nexthop, *tnexthop;
+ struct nexthop *nexthop;
rib_table_info_t *info = srcdest_rnode_table_info(rn);
- int recursing;
struct prefix *p, *src_p;
struct zebra_vrf *zvrf = vrf_info_lookup (re->vrf_id);
if (info->safi != SAFI_UNICAST)
{
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
return ret;
}
/* If install succeeds, update FIB flag for nexthops. */
if (!ret)
{
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
rib_uninstall_kernel (struct route_node *rn, struct route_entry *re)
{
int ret = 0;
- struct nexthop *nexthop, *tnexthop;
+ struct nexthop *nexthop;
rib_table_info_t *info = srcdest_rnode_table_info(rn);
- int recursing;
struct prefix *p, *src_p;
struct zebra_vrf *zvrf = vrf_info_lookup (re->vrf_id);
if (info->safi != SAFI_UNICAST)
{
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
return ret;
}
ret = kernel_route_rib (p, src_p, re, NULL);
zvrf->removals++;
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
return ret;
rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *old, struct route_entry *new)
{
- struct nexthop *nexthop = NULL, *tnexthop;
- int recursing;
+ struct nexthop *nexthop = NULL;
int nh_active = 0;
int installed = 1;
{
int in_fib = 0;
- for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(new->nexthop, nexthop))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
in_fib = 1;
/* Redistribute SELECTED entry */
if (old_selected != new_selected || selected_changed)
{
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
/* Check if we have a FIB route for the destination, otherwise,
* don't redistribute it */
- for (ALL_NEXTHOPS_RO(new_fib ? new_fib->nexthop : NULL, nexthop,
- tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(new_fib ? new_fib->nexthop : NULL, nexthop))
{
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
{
bool is_srcdst = src_p && src_p->prefixlen;
char straddr[PREFIX_STRLEN];
char srcaddr[PREFIX_STRLEN];
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
zlog_debug ("%s: dumping RE entry %p for %s%s%s vrf %u", func, (const void *)re,
prefix2str(pp, straddr, sizeof(straddr)),
re->nexthop_active_num
);
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
inet_ntop (p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN);
zlog_debug
(
"%s: %s %s with flags %s%s%s",
func,
- (recursing ? " NH" : "NH"),
+ (nexthop->rparent ? " NH" : "NH"),
straddr,
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
struct route_entry *re;
struct route_entry *fib = NULL;
struct route_entry *same = NULL;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
char buf2[INET6_ADDRSTRLEN];
assert(!src_p || afi == AFI_IP6);
same = re;
break;
}
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) ||
IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate))
{
struct zserv *client;
char bufn[INET6_ADDRSTRLEN];
struct listnode *node;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
if (re && (rnh->state == NULL))
{
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
state_changed = 1;
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
{
struct route_entry *re;
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
char buf[SRCDEST2STR_BUFFER];
struct zebra_vrf *zvrf;
vty_out (vty, " ago%s", VTY_NEWLINE);
}
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
- {
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
+ {
char addrstr[32];
vty_out (vty, " %c%s",
- CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ',
- recursing ? " " : "");
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ',
+ nexthop->rparent ? " " : "");
switch (nexthop->type)
{
vty_show_ip_route (struct vty *vty, struct route_node *rn, struct route_entry *re,
json_object *json)
{
- struct nexthop *nexthop, *tnexthop;
- int recursing;
+ struct nexthop *nexthop;
int len = 0;
char buf[SRCDEST2STR_BUFFER];
json_object *json_nexthops = NULL;
json_object_string_add(json_route, "uptime", buf);
}
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
json_nexthop = json_object_new_object();
}
/* Nexthop information. */
- for (ALL_NEXTHOPS_RO(re->nexthop, nexthop, tnexthop, recursing))
+ for (ALL_NEXTHOPS_RO(re->nexthop, nexthop))
{
if (nexthop == re->nexthop)
{
}
else
vty_out (vty, " %c%*c",
- CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
- ? '*' : ' ',
- len - 3 + (2 * recursing), ' ');
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
+ ? '*' : ' ',
+ len - 3 + (2 * (nexthop->rparent ? 1 : 0)), ' ');
switch (nexthop->type)
{