summaryrefslogtreecommitdiffstats
path: root/zebra/zebra_rib.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--zebra/zebra_rib.c264
1 files changed, 161 insertions, 103 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 6538b5e..5b95d86 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -5,6 +5,10 @@
#include <zebra.h>
+#ifdef GNU_LINUX
+#include <linux/rtnetlink.h>
+#endif
+
#include "command.h"
#include "if.h"
#include "linklist.h"
@@ -25,6 +29,7 @@
#include "frr_pthread.h"
#include "printfrr.h"
#include "frrscript.h"
+#include "frrdistance.h"
#include "zebra/zebra_router.h"
#include "zebra/connected.h"
@@ -103,6 +108,9 @@ static const struct {
[ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT,
ZEBRA_CONNECT_DISTANCE_DEFAULT,
META_QUEUE_CONNECTED},
+ [ZEBRA_ROUTE_LOCAL] = {ZEBRA_ROUTE_LOCAL,
+ ZEBRA_CONNECT_DISTANCE_DEFAULT,
+ META_QUEUE_CONNECTED},
[ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC,
ZEBRA_STATIC_DISTANCE_DEFAULT,
META_QUEUE_STATIC},
@@ -130,6 +138,7 @@ static const struct {
[ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, ZEBRA_MAX_DISTANCE_DEFAULT,
META_QUEUE_OTHER},
[ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, ZEBRA_TABLE_DISTANCE_DEFAULT, META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_TABLE_DIRECT] = {ZEBRA_ROUTE_TABLE_DIRECT, ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT, META_QUEUE_STATIC},
[ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, ZEBRA_LDP_DISTANCE_DEFAULT,
META_QUEUE_OTHER},
[ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, ZEBRA_EBGP_DISTANCE_DEFAULT,
@@ -177,6 +186,7 @@ struct wq_nhg_wrapper {
struct nhg_ctx *ctx;
struct nhg_hash_entry *nhe;
} u;
+ bool deletion;
};
#define WQ_NHG_WRAPPER_TYPE_CTX 0x01
@@ -330,7 +340,7 @@ static char *_dump_re_status(const struct route_entry *re, char *buf,
: "",
CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING)
- ? "Replacing"
+ ? "Replacing "
: "",
CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
: "",
@@ -521,7 +531,8 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
if (rn)
route_lock_node(rn);
} else {
- if (match->type != ZEBRA_ROUTE_CONNECT) {
+ if (match->type != ZEBRA_ROUTE_CONNECT &&
+ match->type != ZEBRA_ROUTE_LOCAL) {
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
return NULL;
@@ -623,7 +634,8 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
if (!match)
return NULL;
- if (match->type == ZEBRA_ROUTE_CONNECT)
+ if (match->type == ZEBRA_ROUTE_CONNECT ||
+ match->type == ZEBRA_ROUTE_LOCAL)
return match;
if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED))
@@ -1122,27 +1134,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
}
-/* Check if 'alternate' RIB entry is better than 'current'. */
-static struct route_entry *rib_choose_best(struct route_entry *current,
- struct route_entry *alternate)
+static struct route_entry *rib_choose_best_type(uint8_t route_type,
+ struct route_entry *current,
+ struct route_entry *alternate)
{
- if (current == NULL)
- return alternate;
-
- /* filter route selection in following order:
- * - connected beats other types
- * - if both connected, loopback or vrf wins
- * - lower distance beats higher
- * - lower metric beats higher for equal distance
- * - last, hence oldest, route wins tie break.
- */
-
- /* Connected routes. Check to see if either are a vrf
- * or loopback interface. If not, pick the last connected
- * route of the set of lowest metric connected routes.
+ /*
+ * We know that alternate and current are now non-NULL
*/
- if (alternate->type == ZEBRA_ROUTE_CONNECT) {
- if (current->type != ZEBRA_ROUTE_CONNECT)
+ if (alternate->type == route_type) {
+ if (current->type != route_type)
return alternate;
/* both are connected. are either loop or vrf? */
@@ -1171,7 +1171,41 @@ static struct route_entry *rib_choose_best(struct route_entry *current,
return current;
}
- if (current->type == ZEBRA_ROUTE_CONNECT)
+ return NULL;
+}
+
+/* Check if 'alternate' RIB entry is better than 'current'. */
+static struct route_entry *rib_choose_best(struct route_entry *current,
+ struct route_entry *alternate)
+{
+ struct route_entry *possible;
+
+ if (current == NULL)
+ return alternate;
+
+ /* filter route selection in following order:
+ * - Local beats Connected
+ * - connected beats other types
+ * - if both connected, loopback or vrf wins
+ * - lower distance beats higher
+ * - lower metric beats higher for equal distance
+ * - last, hence oldest, route wins tie break.
+ */
+
+ /* Connected or Local routes. Check to see if either are a vrf
+ * or loopback interface. If not, pick the last connected
+ * route of the set of lowest metric connected routes.
+ */
+ possible = rib_choose_best_type(ZEBRA_ROUTE_LOCAL, current, alternate);
+ if (possible)
+ return possible;
+
+ possible = rib_choose_best_type(ZEBRA_ROUTE_CONNECT, current, alternate);
+ if (possible)
+ return possible;
+
+ if (current->type == ZEBRA_ROUTE_CONNECT ||
+ current->type == ZEBRA_ROUTE_LOCAL)
return current;
/* higher distance loses */
@@ -1200,6 +1234,7 @@ static void rib_process(struct route_node *rn)
rib_dest_t *dest;
struct zebra_vrf *zvrf = NULL;
struct vrf *vrf;
+ struct route_entry *proto_re_changed = NULL;
vrf_id_t vrf_id = VRF_UNKNOWN;
@@ -1269,6 +1304,7 @@ static void rib_process(struct route_node *rn)
* skip it.
*/
if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
+ proto_re_changed = re;
if (!nexthop_active_update(rn, re)) {
const struct prefix *p;
struct rib_table_info *info;
@@ -1354,6 +1390,8 @@ static void rib_process(struct route_node *rn)
* new_selected --- RE entry that is newly SELECTED
* old_fib --- RE entry currently in kernel FIB
* new_fib --- RE entry that is newly to be in kernel FIB
+ * proto_re_changed -- RE that is the last changed entry in the
+ * list of RE's.
*
* new_selected will get SELECTED flag, and is going to be redistributed
* the zclients. new_fib (which can be new_selected) will be installed
@@ -1408,6 +1446,22 @@ static void rib_process(struct route_node *rn)
}
}
+ /*
+ * If zebra has a new_selected and a proto_re_changed
+ * entry that was not the old selected and the protocol
+ * is different, zebra should notify the upper level
+ * protocol that the sent down entry was not selected
+ */
+ if (new_selected && proto_re_changed &&
+ proto_re_changed != old_selected &&
+ new_selected->type != proto_re_changed->type) {
+ struct rib_table_info *info = srcdest_rnode_table_info(rn);
+
+ zsend_route_notify_owner(rn, proto_re_changed,
+ ZAPI_ROUTE_BETTER_ADMIN_WON, info->afi,
+ info->safi);
+ }
+
/* Update fib according to selection results */
if (new_fib && old_fib)
rib_process_update_fib(zvrf, rn, old_fib, new_fib);
@@ -1506,7 +1560,8 @@ static bool rib_route_match_ctx(const struct route_entry *re,
} else if (re->type == ZEBRA_ROUTE_KERNEL &&
re->metric != dplane_ctx_get_metric(ctx)) {
result = false;
- } else if (re->type == ZEBRA_ROUTE_CONNECT) {
+ } else if (re->type == ZEBRA_ROUTE_CONNECT ||
+ re->type == ZEBRA_ROUTE_LOCAL) {
result = nexthop_group_equal_no_recurse(
&re->nhe->nhg, dplane_ctx_get_ng(ctx));
}
@@ -1564,7 +1619,7 @@ static bool rib_compare_routes(const struct route_entry *re1,
* v6 link-locals, and we also support multiple addresses in the same
* subnet on a single interface.
*/
- if (re1->type != ZEBRA_ROUTE_CONNECT)
+ if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
return true;
return false;
@@ -2014,9 +2069,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED);
}
- switch (op) {
- case DPLANE_OP_ROUTE_INSTALL:
- case DPLANE_OP_ROUTE_UPDATE:
+ if (op == DPLANE_OP_ROUTE_INSTALL || op == DPLANE_OP_ROUTE_UPDATE) {
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
if (re) {
UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
@@ -2107,8 +2160,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn);
}
- break;
- case DPLANE_OP_ROUTE_DELETE:
+ } else if (op == DPLANE_OP_ROUTE_DELETE) {
rt_delete = true;
if (re)
SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
@@ -2147,61 +2199,6 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if ((re && RIB_SYSTEM_ROUTE(re)) ||
(old_re && RIB_SYSTEM_ROUTE(old_re)))
zebra_rib_fixup_system(rn);
- break;
-
- case DPLANE_OP_NONE:
- case DPLANE_OP_ROUTE_NOTIFY:
- case DPLANE_OP_NH_INSTALL:
- case DPLANE_OP_NH_UPDATE:
- case DPLANE_OP_NH_DELETE:
- case DPLANE_OP_LSP_INSTALL:
- case DPLANE_OP_LSP_UPDATE:
- case DPLANE_OP_LSP_DELETE:
- case DPLANE_OP_LSP_NOTIFY:
- case DPLANE_OP_PW_INSTALL:
- case DPLANE_OP_PW_UNINSTALL:
- case DPLANE_OP_SYS_ROUTE_ADD:
- case DPLANE_OP_SYS_ROUTE_DELETE:
- case DPLANE_OP_ADDR_INSTALL:
- case DPLANE_OP_ADDR_UNINSTALL:
- case DPLANE_OP_MAC_INSTALL:
- case DPLANE_OP_MAC_DELETE:
- case DPLANE_OP_NEIGH_INSTALL:
- case DPLANE_OP_NEIGH_UPDATE:
- case DPLANE_OP_NEIGH_DELETE:
- case DPLANE_OP_VTEP_ADD:
- case DPLANE_OP_VTEP_DELETE:
- case DPLANE_OP_RULE_ADD:
- case DPLANE_OP_RULE_DELETE:
- case DPLANE_OP_RULE_UPDATE:
- case DPLANE_OP_NEIGH_DISCOVER:
- case DPLANE_OP_BR_PORT_UPDATE:
- case DPLANE_OP_IPTABLE_ADD:
- case DPLANE_OP_IPTABLE_DELETE:
- case DPLANE_OP_IPSET_ADD:
- case DPLANE_OP_IPSET_DELETE:
- case DPLANE_OP_IPSET_ENTRY_ADD:
- case DPLANE_OP_IPSET_ENTRY_DELETE:
- case DPLANE_OP_NEIGH_IP_INSTALL:
- case DPLANE_OP_NEIGH_IP_DELETE:
- case DPLANE_OP_NEIGH_TABLE_UPDATE:
- case DPLANE_OP_GRE_SET:
- case DPLANE_OP_INTF_ADDR_ADD:
- case DPLANE_OP_INTF_ADDR_DEL:
- case DPLANE_OP_INTF_NETCONFIG:
- case DPLANE_OP_INTF_INSTALL:
- case DPLANE_OP_INTF_UPDATE:
- case DPLANE_OP_INTF_DELETE:
- case DPLANE_OP_TC_QDISC_INSTALL:
- case DPLANE_OP_TC_QDISC_UNINSTALL:
- case DPLANE_OP_TC_CLASS_ADD:
- case DPLANE_OP_TC_CLASS_DELETE:
- case DPLANE_OP_TC_CLASS_UPDATE:
- case DPLANE_OP_TC_FILTER_ADD:
- case DPLANE_OP_TC_FILTER_DELETE:
- case DPLANE_OP_TC_FILTER_UPDATE:
- case DPLANE_OP_STARTUP_STAGE:
- break;
}
zebra_rib_evaluate_rn_nexthops(rn, seq, rt_delete);
@@ -2535,7 +2532,7 @@ static void process_subq_evpn(struct listnode *lnode)
static void process_subq_nhg(struct listnode *lnode)
{
struct nhg_ctx *ctx;
- struct nhg_hash_entry *nhe, *newnhe;
+ struct nhg_hash_entry *nhe, *newnhe, *oldnhe;
struct wq_nhg_wrapper *w;
uint8_t qindex = META_QUEUE_NHG;
@@ -2567,15 +2564,33 @@ static void process_subq_nhg(struct listnode *lnode)
subqueue2str(qindex));
/* Process incoming nhg update, probably from a proto daemon */
- newnhe = zebra_nhg_proto_add(nhe->id, nhe->type,
- nhe->zapi_instance,
- nhe->zapi_session, &nhe->nhg, 0);
+ if (w->deletion) {
+ /*
+ * Delete the received nhg id
+ */
+ oldnhe = zebra_nhg_proto_del(nhe->id, nhe->type);
+ if (oldnhe) {
+ zsend_nhg_notify(nhe->type, nhe->zapi_instance,
+ nhe->zapi_session, nhe->id,
+ ZAPI_NHG_REMOVED);
+ zebra_nhg_decrement_ref(oldnhe);
+ } else
+ zsend_nhg_notify(nhe->type, nhe->zapi_instance,
+ nhe->zapi_session, nhe->id,
+ ZAPI_NHG_REMOVE_FAIL);
- /* Report error to daemon via ZAPI */
- if (newnhe == NULL)
- zsend_nhg_notify(nhe->type, nhe->zapi_instance,
- nhe->zapi_session, nhe->id,
- ZAPI_NHG_FAIL_INSTALL);
+ } else {
+ newnhe = zebra_nhg_proto_add(nhe->id, nhe->type,
+ nhe->zapi_instance,
+ nhe->zapi_session,
+ &nhe->nhg, 0);
+
+ /* Report error to daemon via ZAPI */
+ if (newnhe == NULL)
+ zsend_nhg_notify(nhe->type, nhe->zapi_instance,
+ nhe->zapi_session, nhe->id,
+ ZAPI_NHG_FAIL_INSTALL);
+ }
/* Free temp nhe - we own that memory. */
zebra_nhg_free(nhe);
@@ -2678,6 +2693,7 @@ static void early_route_memory_free(struct zebra_early_route *ere)
if (ere->re_nhe)
zebra_nhg_free(ere->re_nhe);
+ zapi_re_opaque_free(ere->re->opaque);
XFREE(MTYPE_RE, ere->re);
XFREE(MTYPE_WQ_WRAPPER, ere);
}
@@ -2859,11 +2875,10 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
rib_addnode(rn, re, 1);
+ dest = rib_dest_from_rnode(rn);
/* Free implicit route.*/
if (same) {
- rib_dest_t *dest = rn->info;
-
- if (same == dest->selected_fib)
+ if (dest && same == dest->selected_fib)
SET_FLAG(same->status, ROUTE_ENTRY_ROUTE_REPLACING);
rib_delnode(rn, same);
}
@@ -2871,7 +2886,6 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
/* See if we can remove some RE entries that are queued for
* removal, but won't be considered in rib processing.
*/
- dest = rib_dest_from_rnode(rn);
RNODE_FOREACH_RE_SAFE (rn, re, same) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
/* If the route was used earlier, must retain it. */
@@ -2967,7 +2981,8 @@ static void process_subq_early_route_delete(struct zebra_early_route *ere)
if (re->type == ZEBRA_ROUTE_KERNEL &&
re->metric != ere->re->metric)
continue;
- if (re->type == ZEBRA_ROUTE_CONNECT &&
+ if ((re->type == ZEBRA_ROUTE_CONNECT ||
+ re->type == ZEBRA_ROUTE_LOCAL) &&
(rtnh = re->nhe->nhg.nexthop) &&
rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) {
if (rtnh->ifindex != nh->ifindex)
@@ -3342,7 +3357,8 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data)
return 0;
}
-static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
+static int rib_meta_queue_nhg_process(struct meta_queue *mq, void *data,
+ bool deletion)
{
struct nhg_hash_entry *nhe = NULL;
uint8_t qindex = META_QUEUE_NHG;
@@ -3357,6 +3373,7 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
w->type = WQ_NHG_WRAPPER_TYPE_NHG;
w->u.nhe = nhe;
+ w->deletion = deletion;
listnode_add(mq->subq[qindex], w);
mq->size++;
@@ -3368,6 +3385,16 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
return 0;
}
+static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
+{
+ return rib_meta_queue_nhg_process(mq, data, false);
+}
+
+static int rib_meta_queue_nhg_del(struct meta_queue *mq, void *data)
+{
+ return rib_meta_queue_nhg_process(mq, data, true);
+}
+
static int rib_meta_queue_evpn_add(struct meta_queue *mq, void *data)
{
listnode_add(mq->subq[META_QUEUE_EVPN], data);
@@ -3476,6 +3503,17 @@ int rib_queue_nhe_add(struct nhg_hash_entry *nhe)
}
/*
+ * Enqueue incoming nhg from proto daemon for processing
+ */
+int rib_queue_nhe_del(struct nhg_hash_entry *nhe)
+{
+ if (nhe == NULL)
+ return -1;
+
+ return mq_add_handler(nhe, rib_meta_queue_nhg_del);
+}
+
+/*
* Enqueue evpn route for processing
*/
int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
@@ -4083,7 +4121,6 @@ static void _route_entry_dump_nh(const struct route_entry *re,
ifp ? ifp->name : "Unknown");
break;
case NEXTHOP_TYPE_IPV4:
- /* fallthrough */
case NEXTHOP_TYPE_IPV4_IFINDEX:
inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
break;
@@ -4267,6 +4304,12 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type,
return re;
}
+
+void zebra_rib_route_entry_free(struct route_entry *re)
+{
+ XFREE(MTYPE_RE, re);
+}
+
/*
* Internal route-add implementation; there are a couple of different public
* signatures. Callers in this path are responsible for the memory they
@@ -4917,6 +4960,7 @@ static void rib_process_dplane_results(struct event *thread)
case DPLANE_OP_BR_PORT_UPDATE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
+ case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET:
case DPLANE_OP_NONE:
break;
case DPLANE_OP_STARTUP_STAGE:
@@ -4979,7 +5023,7 @@ static void check_route_info(void)
}
/* Routing information base initialize. */
-void rib_init(void)
+void zebra_rib_init(void)
{
check_route_info();
@@ -4991,6 +5035,20 @@ void rib_init(void)
zebra_dplane_init(rib_dplane_results);
}
+void zebra_rib_terminate(void)
+{
+ struct zebra_dplane_ctx *ctx;
+
+ EVENT_OFF(t_dplane);
+
+ ctx = dplane_ctx_dequeue(&rib_dplane_q);
+ while (ctx) {
+ dplane_ctx_fini(&ctx);
+
+ ctx = dplane_ctx_dequeue(&rib_dplane_q);
+ }
+}
+
/*
* vrf_id_get_next
*
@@ -5044,7 +5102,7 @@ struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter)
iter->vrf_id = VRF_DEFAULT;
iter->afi_safi_ix = -1;
- /* Fall through */
+ fallthrough;
case RIB_TABLES_ITER_S_ITERATING:
iter->afi_safi_ix++;