forked from Mirror/frr
zebra: Handle kernel routes appropriately
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 <sharpd@nvidia.com>
This commit is contained in:
parent
bdfccf69fa
commit
d528c02a20
|
@ -1058,6 +1058,8 @@ void if_down(struct interface *ifp)
|
||||||
|
|
||||||
/* Delete all neighbor addresses learnt through IPv6 RA */
|
/* Delete all neighbor addresses learnt through IPv6 RA */
|
||||||
if_down_del_nbr_connected(ifp);
|
if_down_del_nbr_connected(ifp);
|
||||||
|
|
||||||
|
rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void if_refresh(struct interface *ifp)
|
void if_refresh(struct interface *ifp)
|
||||||
|
|
|
@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ {
|
||||||
|
|
||||||
/* Events/reasons triggering a RIB update. */
|
/* Events/reasons triggering a RIB update. */
|
||||||
enum rib_update_event {
|
enum rib_update_event {
|
||||||
|
RIB_UPDATE_INTERFACE_DOWN,
|
||||||
RIB_UPDATE_KERNEL,
|
RIB_UPDATE_KERNEL,
|
||||||
RIB_UPDATE_RMAP_CHANGE,
|
RIB_UPDATE_RMAP_CHANGE,
|
||||||
RIB_UPDATE_OTHER,
|
RIB_UPDATE_OTHER,
|
||||||
|
|
|
@ -799,8 +799,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
||||||
return 0;
|
return 0;
|
||||||
if (rtm->rtm_protocol == RTPROT_REDIRECT)
|
if (rtm->rtm_protocol == RTPROT_REDIRECT)
|
||||||
return 0;
|
return 0;
|
||||||
if (rtm->rtm_protocol == RTPROT_KERNEL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
selfroute = is_selfroute(rtm->rtm_protocol);
|
selfroute = is_selfroute(rtm->rtm_protocol);
|
||||||
|
|
||||||
|
|
|
@ -1619,6 +1619,10 @@ static bool rib_compare_routes(const struct route_entry *re1,
|
||||||
* v6 link-locals, and we also support multiple addresses in the same
|
* v6 link-locals, and we also support multiple addresses in the same
|
||||||
* subnet on a single interface.
|
* subnet on a single interface.
|
||||||
*/
|
*/
|
||||||
|
if (re1->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)
|
if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -2863,10 +2867,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
|
||||||
|
|
||||||
/* Link new re to node.*/
|
/* Link new re to node.*/
|
||||||
if (IS_ZEBRA_DEBUG_RIB) {
|
if (IS_ZEBRA_DEBUG_RIB) {
|
||||||
rnode_debug(
|
rnode_debug(rn, re->vrf_id,
|
||||||
rn, re->vrf_id,
|
"Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d",
|
||||||
"Inserting route rn %p, re %p (%s) existing %p, same_count %d",
|
rn, re, zebra_route_string(re->type),
|
||||||
rn, re, zebra_route_string(re->type), same, same_count);
|
afi2str(ere->afi), safi2str(ere->safi), same,
|
||||||
|
same_count);
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||||
route_entry_dump(
|
route_entry_dump(
|
||||||
|
@ -4383,6 +4388,34 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||||
nhe.id = re->nhe_id;
|
nhe.id = re->nhe_id;
|
||||||
|
|
||||||
n = zebra_nhe_copy(&nhe, 0);
|
n = zebra_nhe_copy(&nhe, 0);
|
||||||
|
|
||||||
|
if (re->type == ZEBRA_ROUTE_KERNEL) {
|
||||||
|
struct interface *ifp;
|
||||||
|
struct connected *connected;
|
||||||
|
|
||||||
|
if (p->family == AF_INET6 &&
|
||||||
|
IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) {
|
||||||
|
zebra_nhg_free(n);
|
||||||
|
zebra_rib_route_entry_free(re);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifp = if_lookup_prefix(p, re->vrf_id);
|
||||||
|
if (ifp) {
|
||||||
|
connected = connected_lookup_prefix(ifp, p);
|
||||||
|
|
||||||
|
if (connected && !CHECK_FLAG(connected->flags,
|
||||||
|
ZEBRA_IFA_NOPREFIXROUTE)) {
|
||||||
|
zebra_nhg_free(n);
|
||||||
|
zebra_rib_route_entry_free(re);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifp->ifindex == ng->nexthop->ifindex)
|
||||||
|
re->type = ZEBRA_ROUTE_CONNECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);
|
ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);
|
||||||
|
|
||||||
/* In error cases, free the route also */
|
/* In error cases, free the route also */
|
||||||
|
@ -4458,6 +4491,9 @@ static const char *rib_update_event2str(enum rib_update_event event)
|
||||||
const char *ret = "UNKNOWN";
|
const char *ret = "UNKNOWN";
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
case RIB_UPDATE_INTERFACE_DOWN:
|
||||||
|
ret = "RIB_UPDATE_INTERFACE_DOWN";
|
||||||
|
break;
|
||||||
case RIB_UPDATE_KERNEL:
|
case RIB_UPDATE_KERNEL:
|
||||||
ret = "RIB_UPDATE_KERNEL";
|
ret = "RIB_UPDATE_KERNEL";
|
||||||
break;
|
break;
|
||||||
|
@ -4474,15 +4510,56 @@ static const char *rib_update_event2str(enum rib_update_event event)
|
||||||
return ret;
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
/* 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;
|
struct route_entry *re, *next;
|
||||||
bool re_changed = false;
|
bool re_changed = false;
|
||||||
|
|
||||||
RNODE_FOREACH_RE_SAFE (rn, re, next) {
|
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);
|
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
||||||
re_changed = true;
|
re_changed = true;
|
||||||
}
|
}
|
||||||
|
@ -4522,20 +4599,24 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
|
||||||
/*
|
/*
|
||||||
* If we are looking at a route node and the node
|
* If we are looking at a route node and the node
|
||||||
* has already been queued we don't
|
* has already been queued we don't
|
||||||
* need to queue it up again
|
* need to queue it up again, unless it is
|
||||||
|
* an interface down event as that we need
|
||||||
|
* to process this no matter what.
|
||||||
*/
|
*/
|
||||||
if (rn->info
|
if (rn->info &&
|
||||||
&& CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
|
CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
|
||||||
RIB_ROUTE_ANY_QUEUED))
|
RIB_ROUTE_ANY_QUEUED) &&
|
||||||
|
event != RIB_UPDATE_INTERFACE_DOWN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
case RIB_UPDATE_INTERFACE_DOWN:
|
||||||
case RIB_UPDATE_KERNEL:
|
case RIB_UPDATE_KERNEL:
|
||||||
rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
|
rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event);
|
||||||
break;
|
break;
|
||||||
case RIB_UPDATE_RMAP_CHANGE:
|
case RIB_UPDATE_RMAP_CHANGE:
|
||||||
case RIB_UPDATE_OTHER:
|
case RIB_UPDATE_OTHER:
|
||||||
rib_update_route_node(rn, rtype);
|
rib_update_route_node(rn, rtype, event);
|
||||||
break;
|
break;
|
||||||
case RIB_UPDATE_MAX:
|
case RIB_UPDATE_MAX:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue