forked from Mirror/frr
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:
parent
f24fdd9921
commit
915902cb82
|
@ -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;
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue