#include "zebra/zebra_rnh.h"
#include "zebra/interface.h"
#include "zebra/connected.h"
+#include "zebra/zebra_vxlan.h"
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason))
[ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20},
[ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20},
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100},
+ [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150},
/* no entry/default: 150 */
};
struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
- ifindex_t ifindex)
+ ifindex_t ifindex,
+ vrf_id_t nh_vrf_id)
{
struct nexthop *nexthop;
nexthop = nexthop_new();
nexthop->type = NEXTHOP_TYPE_IFINDEX;
nexthop->ifindex = ifindex;
+ nexthop->vrf_id = nh_vrf_id;
route_entry_nexthop_add(re, nexthop);
struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re,
struct in_addr *ipv4,
- struct in_addr *src)
+ struct in_addr *src,
+ vrf_id_t nh_vrf_id)
{
struct nexthop *nexthop;
nexthop = nexthop_new();
nexthop->type = NEXTHOP_TYPE_IPV4;
+ nexthop->vrf_id = nh_vrf_id;
nexthop->gate.ipv4 = *ipv4;
if (src)
nexthop->src.ipv4 = *src;
struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
struct in_addr *ipv4,
struct in_addr *src,
- ifindex_t ifindex)
+ ifindex_t ifindex,
+ vrf_id_t nh_vrf_id)
{
struct nexthop *nexthop;
struct interface *ifp;
nexthop = nexthop_new();
+ nexthop->vrf_id = nh_vrf_id;
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 = *ipv4;
if (src)
nexthop->src.ipv4 = *src;
nexthop->ifindex = ifindex;
- ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+ ifp = if_lookup_by_index(nexthop->ifindex, nh_vrf_id);
/*Pending: need to think if null ifp here is ok during bootup?
There was a crash because ifp here was coming to be NULL */
if (ifp)
- if (connected_is_unnumbered(ifp)) {
+ if (connected_is_unnumbered(ifp)
+ || CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
}
}
struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re,
- struct in6_addr *ipv6)
+ struct in6_addr *ipv6,
+ vrf_id_t nh_vrf_id)
{
struct nexthop *nexthop;
nexthop = nexthop_new();
+ nexthop->vrf_id = nh_vrf_id;
nexthop->type = NEXTHOP_TYPE_IPV6;
nexthop->gate.ipv6 = *ipv6;
struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
struct in6_addr *ipv6,
- ifindex_t ifindex)
+ ifindex_t ifindex,
+ vrf_id_t nh_vrf_id)
{
struct nexthop *nexthop;
nexthop = nexthop_new();
+ nexthop->vrf_id = nh_vrf_id;
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex;
struct nexthop *nexthop;
nexthop = nexthop_new();
+ nexthop->vrf_id = VRF_DEFAULT;
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
nexthop->bh_type = bh_type;
resolved_hop = nexthop_new();
SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+ resolved_hop->vrf_id = nexthop->vrf_id;
switch (newhop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
break;
}
+ /* Copy labels of the resolved route */
+ if (newhop->nh_label)
+ nexthop_add_labels(resolved_hop, newhop->nh_label_type,
+ newhop->nh_label->num_labels,
+ &newhop->nh_label->label[0]);
+
resolved_hop->rparent = nexthop;
nexthop_add(&nexthop->resolved, resolved_hop);
}
if (set) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
- zebra_deregister_rnh_static_nexthops(re->vrf_id,
- nexthop->resolved, top);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
re->nexthop_mtu = 0;
* address in the routing table.
*/
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
- ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+ ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (ifp && connected_is_unnumbered(ifp)) {
if (if_is_operative(ifp))
return 1;
break;
}
/* Lookup table. */
- table = zebra_vrf_table(afi, SAFI_UNICAST, re->vrf_id);
+ table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
if (!table)
return 0;
* host route.
*/
if (top && rn == top)
- if (((afi == AFI_IP) && (rn->p.prefixlen != 32)) ||
- ((afi == AFI_IP6) && (rn->p.prefixlen != 128)))
+ if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
+ || ((afi == AFI_IP6) && (rn->p.prefixlen != 128)))
return 0;
/* Pick up selected route. */
/* However, do not resolve over default route unless explicitly
* allowed. */
if (is_default_prefix(&rn->p)
- && !nh_resolve_via_default(p.family))
+ && !rnh_resolve_via_default(p.family))
return 0;
dest = rib_dest_from_rnode(rn);
- if (dest && dest->selected_fib &&
- !CHECK_FLAG(dest->selected_fib->status,
- ROUTE_ENTRY_REMOVED) &&
- dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
+ if (dest && dest->selected_fib
+ && !CHECK_FLAG(dest->selected_fib->status,
+ ROUTE_ENTRY_REMOVED)
+ && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
match = dest->selected_fib;
/* If there is no selected route or matched route is EGP, go up
nexthop->ifindex = newhop->ifindex;
}
return 1;
- } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) {
+ } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
resolved = 0;
for (ALL_NEXTHOPS(match->nexthop, newhop)) {
if (!CHECK_FLAG(newhop->flags,
route_unlock_node(rn);
dest = rib_dest_from_rnode(rn);
- if (dest && dest->selected_fib &&
- !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+ if (dest && dest->selected_fib
+ && !CHECK_FLAG(dest->selected_fib->status,
+ ROUTE_ENTRY_REMOVED))
match = dest->selected_fib;
/* If there is no selected route or matched route is EGP, go up
route_unlock_node(rn);
dest = rib_dest_from_rnode(rn);
- if (dest && dest->selected_fib &&
- !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+ if (dest && dest->selected_fib
+ && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
match = dest->selected_fib;
if (!match)
/* Find out if a "selected" RR for the discovered RIB entry exists ever.
*/
- if (dest && dest->selected_fib &&
- !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+ if (dest && dest->selected_fib
+ && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
match = dest->selected_fib;
/* None such found :( */
family = 0;
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
- ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+ ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (ifp && if_is_operative(ifp))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP;
- if (nexthop_active(AFI_IP, re, nexthop, set, rn))
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ else if (nexthop_active(AFI_IP, re, nexthop, set, rn))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
if (rn->p.family != AF_INET)
family = AFI_IP6;
if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
- ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+ ifp = if_lookup_by_index(nexthop->ifindex,
+ nexthop->vrf_id);
if (ifp && if_is_operative(ifp))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
/* It'll get set if required inside */
- ret = zebra_route_map_check(family, re->type, p, nexthop, re->vrf_id,
- re->tag);
+ ret = zebra_route_map_check(family, re->type, p, nexthop,
+ nexthop->vrf_id, re->tag);
if (ret == RMAP_DENYMATCH) {
if (IS_ZEBRA_DEBUG_RIB) {
srcdest_rnode2str(rn, buf, sizeof(buf));
zlog_debug(
"%u:%s: Filtering out with NH out %s due to route map",
re->vrf_id, buf,
- ifindex2ifname(nexthop->ifindex, re->vrf_id));
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
}
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
return 1;
}
-void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re,
+void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p,
+ struct route_entry *re,
enum southbound_results res)
{
struct nexthop *nexthop;
char buf[PREFIX_STRLEN];
+ rib_dest_t *dest;
+
+ dest = rib_dest_from_rnode(rn);
switch (res) {
case SOUTHBOUND_INSTALL_SUCCESS:
+ dest->selected_fib = re;
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
- zsend_route_notify_owner(re->type, re->instance, re->vrf_id,
- p, ZAPI_ROUTE_INSTALLED);
+ zsend_route_notify_owner(re, p, ZAPI_ROUTE_INSTALLED);
break;
case SOUTHBOUND_INSTALL_FAILURE:
- zsend_route_notify_owner(re->type, re->instance, re->vrf_id,
- p, ZAPI_ROUTE_FAIL_INSTALL);
+ /*
+ * I am not sure this is the right thing to do here
+ * but the code always set selected_fib before
+ * this assignment was moved here.
+ */
+ dest->selected_fib = re;
+
+ zsend_route_notify_owner(re, p, ZAPI_ROUTE_FAIL_INSTALL);
zlog_warn("%u:%s: Route install failed", re->vrf_id,
prefix2str(p, buf, sizeof(buf)));
break;
case SOUTHBOUND_DELETE_SUCCESS:
+ /*
+ * The case where selected_fib is not re is
+ * when we have received a system route
+ * that is overriding our installed route
+ * as such we should leave the selected_fib
+ * pointer alone
+ */
+ if (dest->selected_fib == re)
+ dest->selected_fib = NULL;
for (ALL_NEXTHOPS(re->nexthop, nexthop))
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
break;
case SOUTHBOUND_DELETE_FAILURE:
+ /*
+ * Should we set this to NULL if the
+ * delete fails?
+ */
+ dest->selected_fib = NULL;
zlog_warn("%u:%s: Route Deletion failure", re->vrf_id,
prefix2str(p, buf, sizeof(buf)));
break;
struct nexthop *prev;
for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
for (ALL_NEXTHOPS(re->nexthop, prev)) {
if (prev == nexthop)
break;
- if (nexthop_same_firsthop (nexthop, prev))
- {
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE);
+ if (nexthop_same_firsthop(nexthop, prev)) {
+ SET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_DUPLICATE);
break;
}
}
* If this is a replace to a new RE let the originator of the RE
* know that they've lost
*/
- if (old && old != re)
- zsend_route_notify_owner(old->type, old->instance,
- old->vrf_id, p,
- ZAPI_ROUTE_BETTER_ADMIN_WON);
+ if (old && (old != re) && (old->type != re->type))
+ zsend_route_notify_owner(old, p, ZAPI_ROUTE_BETTER_ADMIN_WON);
/*
* Make sure we update the FPM any time we send new information to
* the kernel.
*/
hook_call(rib_update, rn, "installing in kernel");
- kernel_route_rib(p, src_p, old, re);
+ kernel_route_rib(rn, p, src_p, old, re);
zvrf->installs++;
return;
* the kernel.
*/
hook_call(rib_update, rn, "uninstalling from kernel");
- kernel_route_rib(p, src_p, re, NULL);
- zvrf->removals++;
+ kernel_route_rib(rn, p, src_p, re, NULL);
+ if (zvrf)
+ zvrf->removals++;
return;
}
/* If labeled-unicast route, uninstall transit LSP. */
if (zebra_rib_labeled_unicast(re))
zebra_mpls_lsp_uninstall(info->zvrf, rn, re);
-
- dest->selected_fib = NULL;
}
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
return;
}
- dest->selected_fib = new;
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
if (!RIB_SYSTEM_ROUTE(new))
rib_install_kernel(rn, new, NULL);
+ else
+ dest->selected_fib = new;
UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
}
if (!RIB_SYSTEM_ROUTE(old))
rib_uninstall_kernel(rn, old);
-
- dest->selected_fib = NULL;
+ else {
+ /*
+ * We are setting this to NULL here
+ * because that is what we traditionally
+ * have been doing. I am not positive
+ * that this is the right thing to do
+ * but let's leave the code alone
+ * for the RIB_SYSTEM_ROUTE case
+ */
+ dest->selected_fib = NULL;
+ }
/* Update nexthop for route, reset changed flag. */
nexthop_active_update(rn, old, 1);
{
struct nexthop *nexthop = NULL;
int nh_active = 0;
- int installed = 1;
rib_dest_t *dest = rib_dest_from_rnode(rn);
/*
zebra_mpls_lsp_install(zvrf, rn, new);
rib_install_kernel(rn, new, old);
+ } else {
+ /*
+ * We do not need to install the
+ * selected route because it
+ * is already isntalled by
+ * the system( ie not us )
+ * so just mark it as winning
+ * we do need to ensure that
+ * if we uninstall a route
+ * from ourselves we don't
+ * over write this pointer
+ */
+ dest->selected_fib = NULL;
}
-
/* If install succeeded or system route, cleanup flags
* for prior route. */
- if (installed && new != old) {
+ if (new != old) {
if (RIB_SYSTEM_ROUTE(new)) {
if (!RIB_SYSTEM_ROUTE(old))
rib_uninstall_kernel(rn, old);
NEXTHOP_FLAG_FIB);
}
}
-
- /* Update for redistribution. */
- if (installed)
- dest->selected_fib = new;
}
/*
* failed, we
* may need to uninstall and delete for redistribution.
*/
- if (!nh_active || !installed) {
+ if (!nh_active) {
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
if (!RIB_SYSTEM_ROUTE(old))
rib_uninstall_kernel(rn, old);
- dest->selected_fib = NULL;
+ else
+ dest->selected_fib = NULL;
}
} else {
/*
* to add routes.
*/
if (!RIB_SYSTEM_ROUTE(new)) {
- int in_fib = 0;
+ bool in_fib = false;
for (ALL_NEXTHOPS(new->nexthop, nexthop))
if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_FIB)) {
- in_fib = 1;
+ in_fib = true;
break;
}
if (!in_fib)
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%u:%s: Processing rn %p", vrf_id, buf, rn);
- old_fib = dest->selected_fib;
+ /*
+ * we can have rn's that have a NULL info pointer
+ * (dest). As such let's not let the deref happen
+ * additionally we know RNODE_FOREACH_RE_SAFE
+ * will not iterate so we are ok.
+ */
+ if (dest)
+ old_fib = dest->selected_fib;
RNODE_FOREACH_RE_SAFE (rn, re, next) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
dest->routes = re->next;
}
+ if (dest->selected_fib == re)
+ dest->selected_fib = NULL;
+
/* free RE and nexthops */
- zebra_deregister_rnh_static_nexthops(re->vrf_id, re->nexthop, rn);
+ if (re->type == ZEBRA_ROUTE_STATIC)
+ zebra_deregister_rnh_static_nexthops(re->vrf_id, re->nexthop,
+ rn);
nexthops_free(re->nexthop);
XFREE(MTYPE_RE, re);
}
continue;
if (same->instance != re->instance)
continue;
- if (same->type == ZEBRA_ROUTE_KERNEL &&
- same->metric != re->metric)
+ if (same->type == ZEBRA_ROUTE_KERNEL
+ && same->metric != re->metric)
continue;
/*
* We should allow duplicate connected routes because of
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
u_short instance, int flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
- u_int32_t table_id, u_int32_t metric, bool fromkernel)
+ u_int32_t table_id, u_int32_t metric, bool fromkernel,
+ struct ethaddr *rmac)
{
struct route_table *table;
struct route_node *rn;
continue;
if (re->instance != instance)
continue;
- if (re->type == ZEBRA_ROUTE_KERNEL &&
- re->metric != metric)
+ if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric)
continue;
if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->nexthop)
&& rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) {
UNSET_FLAG(rtnh->flags,
NEXTHOP_FLAG_FIB);
+ /*
+ * This is a non FRR route
+ * as such we should mark
+ * it as deleted
+ */
dest->selected_fib = NULL;
} else {
/* This means someone else, other than Zebra,
}
if (same) {
- if (fromkernel &&
- CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) &&
- !allow_delete) {
+ if (fromkernel && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)
+ && !allow_delete) {
rib_install_kernel(rn, same, NULL);
route_unlock_node(rn);
return;
}
+
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ struct nexthop *tmp_nh;
+
+ for (ALL_NEXTHOPS(re->nexthop, tmp_nh)) {
+ struct ipaddr vtep_ip;
+
+ memset(&vtep_ip, 0, sizeof(struct ipaddr));
+ vtep_ip.ipa_type = IPADDR_V4;
+ memcpy(&(vtep_ip.ipaddr_v4),
+ &(tmp_nh->gate.ipv4),
+ sizeof(struct in_addr));
+ zebra_vxlan_evpn_vrf_route_del(re->vrf_id, rmac,
+ &vtep_ip, p);
+ }
+ }
rib_delnode(rn, same);
}
* 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))
continue;
switch (event) {
case RIB_UPDATE_IF_CHANGE:
RNODE_FOREACH_RE_SAFE (rn, re, next) {
struct nexthop *nh;
- if (re->type != ZEBRA_ROUTE_SYSTEM &&
- re->type != ZEBRA_ROUTE_KERNEL &&
- re->type != ZEBRA_ROUTE_CONNECT &&
- re->type != ZEBRA_ROUTE_STATIC)
+ if (re->type != ZEBRA_ROUTE_SYSTEM
+ && re->type != ZEBRA_ROUTE_KERNEL
+ && re->type != ZEBRA_ROUTE_CONNECT
+ && re->type != ZEBRA_ROUTE_STATIC)
continue;
if (re->type != ZEBRA_ROUTE_STATIC) {