diff --git a/lib/zebra.h b/lib/zebra.h index 98428eaab2..edae75207f 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -414,6 +414,7 @@ extern const char *zserv_command_string(unsigned int command); #define ZEBRA_FLAG_SCOPE_LINK 0x100 #define ZEBRA_FLAG_FIB_OVERRIDE 0x200 #define ZEBRA_FLAG_EVPN_ROUTE 0x400 +#define ZEBRA_FLAG_RR_USE_DISTANCE 0x800 /* ZEBRA_FLAG_BLACKHOLE was 0x04 */ /* ZEBRA_FLAG_REJECT was 0x80 */ diff --git a/zebra/connected.c b/zebra/connected.c index 8869d34fd6..57bfcc4d16 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -403,10 +403,10 @@ void connected_down(struct interface *ifp, struct connected *ifc) * head. */ rib_delete(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, &nh, 0, 0, false); + &p, NULL, &nh, 0, 0, 0, false); rib_delete(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, - &p, NULL, &nh, 0, 0, false); + &p, NULL, &nh, 0, 0, 0, false); if (IS_ZEBRA_DEBUG_RIB_DETAILED) { char buf[PREFIX_STRLEN]; diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index b85c4748c4..71d709e72d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1043,7 +1043,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, true); + NULL, 0, 0, 0, true); if (!nh.type) { nh.type = NEXTHOP_TYPE_IPV4; @@ -1058,7 +1058,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, true); + &nh, 0, 0, 0, true); } if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the @@ -1089,7 +1089,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, true); + NULL, 0, 0, 0, true); if (!nh.type) { nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX @@ -1106,7 +1106,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, true); + &nh, 0, 0, 0, true); } } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 69c0ebb7ec..e3101fbe72 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -597,7 +597,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re) rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table, re->flags, &p, NULL, re->ng.nexthop, - zebrad.rtm_table_default, re->metric, false); + zebrad.rtm_table_default, re->metric, re->distance, false); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index 439327aa48..a37b2bf221 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -311,7 +311,8 @@ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, - uint32_t table_id, uint32_t metric, bool fromkernel); + uint32_t table_id, uint32_t metric, uint8_t distance, + bool fromkernel); extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, union g_addr *addr, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5facfa5faa..918152aa6e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -644,12 +644,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (gate) memcpy(&nh.gate, gate, sz); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, &src_p, &nh, table, metric, true); + &p, &src_p, &nh, table, metric, distance, true); } else { /* XXX: need to compare the entire list of nexthops * here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, &src_p, NULL, table, metric, true); + &p, &src_p, NULL, table, metric, distance, true); } } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index b41cb812cb..ad574d7e8b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1565,7 +1565,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance, api.flags, &api.prefix, src_p, NULL, table_id, api.metric, - false); + api.distance, false); /* Stats */ switch (api.prefix.family) { @@ -1767,7 +1767,7 @@ static void zread_ipv4_delete(ZAPI_HANDLER_ARGS) table_id = zvrf->table_id; rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &p, NULL, NULL, table_id, 0, false); + api.flags, &p, NULL, NULL, table_id, 0, 0, false); client->v4_route_del_cnt++; stream_failure: @@ -2191,7 +2191,7 @@ static void zread_ipv6_delete(ZAPI_HANDLER_ARGS) src_pp = NULL; rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &p, src_pp, NULL, client->rtm_table, 0, false); + api.flags, &p, src_pp, NULL, client->rtm_table, 0, 0, false); client->v6_route_del_cnt++; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 33eebfe99e..18bd6b6cbe 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2321,7 +2321,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, { struct route_table *table; struct route_node *rn; - struct route_entry *same; + struct route_entry *same = NULL; struct nexthop *nexthop; int ret = 0; @@ -2355,8 +2355,13 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup route node.*/ rn = srcdest_rnode_get(table, p, src_p); - /* If same type of route are installed, treat it as a implicit - withdraw. */ + zlog_debug("Distance: %d", re->distance); + /* + * If same type of route are installed, treat it as a implicit + * withdraw. + * If the user has specified the No route replace semantics + * for the install don't do a route replace. + */ RNODE_FOREACH_RE (rn, same) { if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) continue; @@ -2368,14 +2373,21 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (same->type == ZEBRA_ROUTE_KERNEL && same->metric != re->metric) continue; + + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE) && + same->distance != re->distance) + continue; + /* - * We should allow duplicate connected routes because of - * IPv6 link-local routes and unnumbered interfaces on Linux. + * We should allow duplicate connected routes + * because of IPv6 link-local routes and unnumbered + * interfaces on Linux. */ if (same->type != ZEBRA_ROUTE_CONNECT) break; } + zlog_debug("same: %p distance: %d", same, same ? same->distance : -1); /* If this route is kernel route, set FIB flag to the route. */ if (RIB_SYSTEM_ROUTE(re)) for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) @@ -2407,7 +2419,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, - uint32_t table_id, uint32_t metric, bool fromkernel) + uint32_t table_id, uint32_t metric, uint8_t distance, + bool fromkernel) { struct route_table *table; struct route_node *rn; @@ -2461,6 +2474,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, continue; if (re->instance != instance) continue; + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE) && + distance != re->distance) + continue; + if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop)