diff options
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r-- | zebra/zebra_rib.c | 264 |
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++; |