zebra: Allow zebra to delete self originated routes

With the change to make zebra pass routes to the kernel
with the 'correct' proto name, it caused zebra to
not properly recognize them on startup again
the next time such that the route would not
be deleted.

Modify rt_netlink.c to notice that we have a
self originated route and to properly mark
the type of route it was.

Modify rib_table_sweep to mark the nexthops
as active so that when we go to delete the
self originated routes it would properly
delete from the kernel.

Fixes: #1061
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2017-09-01 10:28:19 -04:00
parent f24fdd9921
commit 915902cb82
2 changed files with 101 additions and 26 deletions

View file

@ -148,14 +148,15 @@ static inline int is_selfroute(int proto)
|| (proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA)
|| (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)
|| (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
|| (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)) {
|| (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
|| (proto == RTPROT_RIP)) {
return 1;
}
return 0;
}
static inline int get_rt_proto(int proto)
static inline int zebra2proto(int proto)
{
switch (proto) {
case ZEBRA_ROUTE_BABEL:
@ -197,6 +198,47 @@ static inline int get_rt_proto(int proto)
return proto;
}
static inline int proto2zebra(int proto, int family)
{
switch (proto) {
case RTPROT_BABEL:
proto = ZEBRA_ROUTE_BABEL;
break;
case RTPROT_BGP:
proto = ZEBRA_ROUTE_BGP;
break;
case RTPROT_OSPF:
proto = (family == AFI_IP) ?
ZEBRA_ROUTE_OSPF : ZEBRA_ROUTE_OSPF6;
break;
case RTPROT_ISIS:
proto = ZEBRA_ROUTE_ISIS;
break;
case RTPROT_RIP:
proto = ZEBRA_ROUTE_RIP;
break;
case RTPROT_RIPNG:
proto = ZEBRA_ROUTE_RIPNG;
break;
case RTPROT_NHRP:
proto = ZEBRA_ROUTE_NHRP;
break;
case RTPROT_EIGRP:
proto = ZEBRA_ROUTE_EIGRP;
break;
case RTPROT_LDP:
proto = ZEBRA_ROUTE_LDP;
break;
case RTPROT_STATIC:
proto = ZEBRA_ROUTE_STATIC;
break;
default:
proto = ZEBRA_ROUTE_KERNEL;
break;
}
return proto;
}
/*
Pending: create an efficient table_id (in a tree/hash) based lookup)
*/
@ -231,6 +273,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
char anyaddr[16] = {0};
int proto = ZEBRA_ROUTE_KERNEL;
int index = 0;
int table;
int metric = 0;
@ -300,9 +343,10 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
}
/* Route which inserted by Zebra. */
if (is_selfroute(rtm->rtm_protocol))
if (is_selfroute(rtm->rtm_protocol)) {
flags |= ZEBRA_FLAG_SELFROUTE;
proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family);
}
if (tb[RTA_OIF])
index = *(int *)RTA_DATA(tb[RTA_OIF]);
@ -409,7 +453,8 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
memcpy(&nh.src, prefsrc, sz);
if (gate)
memcpy(&nh.gate, gate, sz);
rib_add(afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
rib_add(afi, SAFI_UNICAST, vrf_id, proto,
0, flags, &p, NULL, &nh, table, metric, mtu, 0);
} else {
/* This is a multipath route */
@ -421,7 +466,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
re->type = ZEBRA_ROUTE_KERNEL;
re->type = proto;
re->distance = 0;
re->flags = flags;
re->metric = metric;
@ -515,13 +560,13 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
if (gate)
memcpy(&nh.gate, gate, sz);
rib_delete(afi, SAFI_UNICAST, vrf_id,
ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, &nh,
proto, 0, flags, &p, NULL, &nh,
table, metric);
} else {
/* XXX: need to compare the entire list of nexthops
* here for NLM_F_APPEND stupidity */
rib_delete(afi, SAFI_UNICAST, vrf_id,
ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, NULL,
proto, 0, flags, &p, NULL, NULL,
table, metric);
}
}
@ -1272,7 +1317,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
req.r.rtm_family = family;
req.r.rtm_dst_len = p->prefixlen;
req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
req.r.rtm_protocol = get_rt_proto(re->type);
req.r.rtm_protocol = zebra2proto(re->type);
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;

View file

@ -2072,8 +2072,9 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
inet_ntop(p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN);
zlog_debug("%s: %s %s with flags %s%s%s", func,
zlog_debug("%s: %s %s[%u] with flags %s%s%s", func,
(nexthop->rparent ? " NH" : "NH"), straddr,
nexthop->ifindex,
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
? "ACTIVE "
: ""),
@ -2644,23 +2645,50 @@ static void rib_sweep_table(struct route_table *table)
struct route_node *rn;
struct route_entry *re;
struct route_entry *next;
struct nexthop *nexthop;
int ret = 0;
if (table)
for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
RNODE_FOREACH_RE_SAFE(rn, re, next)
{
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
continue;
if (!table)
return;
if (re->type == ZEBRA_ROUTE_KERNEL
&& CHECK_FLAG(re->flags,
ZEBRA_FLAG_SELFROUTE)) {
ret = rib_uninstall_kernel(rn, re);
if (!ret)
rib_delnode(rn, re);
}
}
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
RNODE_FOREACH_RE_SAFE(rn, re, next)
{
if (IS_ZEBRA_DEBUG_RIB)
route_entry_dump(&rn->p, NULL, re);
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
continue;
if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELFROUTE))
continue;
/*
* So we are starting up and have received
* routes from the kernel that we have installed
* from a previous run of zebra but not cleaned
* up ( say a kill -9 )
* But since we haven't actually installed
* them yet( we received them from the kernel )
* we don't think they are active.
* So let's pretend they are active to actually
* remove them.
* In all honesty I'm not sure if we should
* mark them as active when we receive them
* This is startup only so probably ok.
*
* If we ever decide to move rib_sweep_table
* to a different spot (ie startup )
* this decision needs to be revisited
*/
for (ALL_NEXTHOPS(re->nexthop, nexthop))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
ret = rib_uninstall_kernel(rn, re);
if (!ret)
rib_delnode(rn, re);
}
}
}
/* Sweep all RIB tables. */
@ -2669,8 +2697,10 @@ void rib_sweep_route(void)
struct vrf *vrf;
struct zebra_vrf *zvrf;
RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id)
if ((zvrf = vrf->info) != NULL) {
RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
if ((zvrf = vrf->info) == NULL)
continue;
rib_sweep_table(zvrf->table[AFI_IP][SAFI_UNICAST]);
rib_sweep_table(zvrf->table[AFI_IP6][SAFI_UNICAST]);
}