Skip to content

Commit

Permalink
zebra: Handle kernel routes appropriately
Browse files Browse the repository at this point in the history
Current code intentionally ignores kernel routes.  Modify
zebra to allow these routes to be read in on linux.  Also
modify zebra to look to see if a route should be treated
as a connected and mark it as such.

Additionally this should properly handle some of the issues
being seen with NOPREFIXROUTE.

Signed-off-by: Donald Sharp <[email protected]>
  • Loading branch information
donaldsharp committed Jun 26, 2024
1 parent bdca985 commit 82b198e
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 15 deletions.
2 changes: 2 additions & 0 deletions zebra/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,8 @@ void if_down(struct interface *ifp)

/* Delete all neighbor addresses learnt through IPv6 RA */
if_down_del_nbr_connected(ifp);

rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL);
}

void if_refresh(struct interface *ifp)
Expand Down
1 change: 1 addition & 0 deletions zebra/rib.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ {

/* Events/reasons triggering a RIB update. */
enum rib_update_event {
RIB_UPDATE_INTERFACE_DOWN,
RIB_UPDATE_KERNEL,
RIB_UPDATE_RMAP_CHANGE,
RIB_UPDATE_OTHER,
Expand Down
2 changes: 0 additions & 2 deletions zebra/rt_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
return 0;
if (rtm->rtm_protocol == RTPROT_KERNEL)
return 0;

selfroute = is_selfroute(rtm->rtm_protocol);

Expand Down
92 changes: 79 additions & 13 deletions zebra/zebra_rib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,8 @@ static void zebra_rib_fixup_system(struct route_node *rn)
}

/* Route comparison logic, with various special cases. */
static bool rib_compare_routes(const struct route_entry *re1,
static bool rib_compare_routes(const struct route_node *rn,
const struct route_entry *re1,
const struct route_entry *re2)
{
if (re1->type != re2->type)
Expand All @@ -1619,6 +1620,11 @@ static bool rib_compare_routes(const struct route_entry *re1,
* v6 link-locals, and we also support multiple addresses in the same
* subnet on a single interface.
*/
if ((re1->type == ZEBRA_ROUTE_CONNECT &&
re2->type == ZEBRA_ROUTE_CONNECT) &&
(re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex))
return true;

if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
return true;

Expand Down Expand Up @@ -2807,7 +2813,7 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
}

/* Compare various route_entry properties */
if (rib_compare_routes(re, same)) {
if (rib_compare_routes(rn, re, same)) {
same_count++;

if (first_same == NULL)
Expand Down Expand Up @@ -2861,10 +2867,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)

/* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
rnode_debug(
rn, re->vrf_id,
"Inserting route rn %p, re %p (%s) existing %p, same_count %d",
rn, re, zebra_route_string(re->type), same, same_count);
rnode_debug(rn, re->vrf_id,
"Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d",
rn, re, zebra_route_string(re->type),
afi2str(ere->afi), safi2str(ere->safi), same,
same_count);

if (IS_ZEBRA_DEBUG_RIB_DETAILED)
route_entry_dump(
Expand Down Expand Up @@ -4373,6 +4380,21 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
nhe.id = re->nhe_id;

n = zebra_nhe_copy(&nhe, 0);

if (re->type == ZEBRA_ROUTE_KERNEL) {
struct interface *ifp;

if (p->family == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) {
XFREE(MTYPE_RE, re);
return -1;
}

ifp = if_lookup_prefix(p, re->vrf_id);
if (ifp)
re->type = ZEBRA_ROUTE_CONNECT;
}

ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);

/* In error cases, free the route also */
Expand Down Expand Up @@ -4448,6 +4470,9 @@ static const char *rib_update_event2str(enum rib_update_event event)
const char *ret = "UNKNOWN";

switch (event) {
case RIB_UPDATE_INTERFACE_DOWN:
ret = "RIB_UPDATE_INTERFACE_DOWN";
break;
case RIB_UPDATE_KERNEL:
ret = "RIB_UPDATE_KERNEL";
break;
Expand All @@ -4464,15 +4489,54 @@ static const char *rib_update_event2str(enum rib_update_event event)
return ret;
}

/*
* We now keep kernel routes, but we don't have any
* trigger events for them when they are implicitly
* deleted. Since we are already walking the
* entire table on a down event let's look at
* the few kernel routes we may have
*/
static void
rib_update_handle_kernel_route_down_possibility(struct route_node *rn,
struct route_entry *re)
{
struct nexthop *nexthop = NULL;
bool alive = false;

for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
struct interface *ifp = if_lookup_by_index(nexthop->ifindex,
nexthop->vrf_id);

if (ifp && if_is_up(ifp))
alive = true;
}

if (!alive) {
struct rib_table_info *rib_table = srcdest_rnode_table_info(rn);
const struct prefix *p;
const struct prefix_ipv6 *src_p;

srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);

rib_delete(rib_table->afi, rib_table->safi, re->vrf_id,
re->type, re->instance, re->flags, p, src_p, NULL, 0,
re->table, re->metric, re->distance, true);
}
}


/* Schedule route nodes to be processed if they match the type */
static void rib_update_route_node(struct route_node *rn, int type)
static void rib_update_route_node(struct route_node *rn, int type,
enum rib_update_event event)
{
struct route_entry *re, *next;
bool re_changed = false;

RNODE_FOREACH_RE_SAFE (rn, re, next) {
if (type == ZEBRA_ROUTE_ALL || type == re->type) {
if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type &&
type == ZEBRA_ROUTE_KERNEL)
rib_update_handle_kernel_route_down_possibility(rn, re);
else if (type == ZEBRA_ROUTE_ALL || type == re->type) {
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
re_changed = true;
}
Expand Down Expand Up @@ -4514,18 +4578,20 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
* has already been queued we don't
* need to queue it up again
*/
if (rn->info
&& CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
RIB_ROUTE_ANY_QUEUED))
if (rn->info &&
CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
RIB_ROUTE_ANY_QUEUED) &&
event != RIB_UPDATE_INTERFACE_DOWN)
continue;

switch (event) {
case RIB_UPDATE_INTERFACE_DOWN:
case RIB_UPDATE_KERNEL:
rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event);
break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
rib_update_route_node(rn, rtype);
rib_update_route_node(rn, rtype, event);
break;
case RIB_UPDATE_MAX:
break;
Expand Down

0 comments on commit 82b198e

Please sign in to comment.