From 22bcedb231390df39c327eba1f12f1da50da0bf2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 25 Jan 2019 20:11:21 -0500 Subject: zebra: Add code to create/remove nexthop groups Add some code to create/remove nexthop groups. Signed-off-by: Stephen Worley --- zebra/zebra_rib.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c2fa33f57d..f385a2d752 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2400,6 +2400,7 @@ static void rib_addnode(struct route_node *rn, void rib_unlink(struct route_node *rn, struct route_entry *re) { rib_dest_t *dest; + rib_table_info_t *info; assert(rn && re); @@ -2414,6 +2415,9 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; + info = srcdest_rnode_table_info(rn); + zebra_nhg_release(info->afi, re); + nexthops_free(re->ng.nexthop); nexthops_free(re->fib_ng.nexthop); @@ -2655,6 +2659,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); + zebra_nhg_find(afi, &re->ng, re); /* Set default distance by route type. */ if (re->distance == 0) re->distance = route_distance(re->type); -- cgit v1.2.3 From 6b46851168ef37eaacba28a2a655e15ae5934cd0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 13 Feb 2019 16:06:48 -0500 Subject: zebra: Replace nexthop_group with pointer in route entry In the route_entry we are keeping a non pointer based nexthop group, switch the code to use a pointer for all operations here and ensure we create and delete the memory. Signed-off-by: Donald Sharp --- zebra/redistribute.c | 7 +++--- zebra/rib.h | 4 ++-- zebra/rt_netlink.c | 6 ++++-- zebra/zapi_msg.c | 15 +++++++++---- zebra/zebra_dplane.c | 4 ++-- zebra/zebra_fpm_netlink.c | 2 +- zebra/zebra_fpm_protobuf.c | 2 +- zebra/zebra_mpls.c | 12 +++++------ zebra/zebra_nhg.c | 10 ++++----- zebra/zebra_pw.c | 2 +- zebra/zebra_rib.c | 54 +++++++++++++++++++++++++--------------------- zebra/zebra_rnh.c | 20 +++++++++-------- zebra/zebra_vty.c | 6 +++--- 13 files changed, 80 insertions(+), 64 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 0dc9de0c59..65b62679e8 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -643,7 +643,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, afi = family2afi(rn->p.family); if (rmap_name) ret = zebra_import_table_route_map_check( - afi, re->type, re->instance, &rn->p, re->ng.nexthop, + afi, re->type, re->instance, &rn->p, re->ng->nexthop, zvrf->vrf->vrf_id, re->tag, rmap_name); if (ret != RMAP_PERMITMATCH) { @@ -679,7 +679,8 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, newre->nexthop_num = 0; newre->uptime = monotime(NULL); newre->instance = re->table; - route_entry_copy_nexthops(newre, re->ng.nexthop); + newre->ng = nexthop_group_new(); + route_entry_copy_nexthops(newre, re->ng->nexthop); rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre); @@ -696,7 +697,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, prefix_copy(&p, &rn->p); rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, - re->table, re->flags, &p, NULL, re->ng.nexthop, + re->table, re->flags, &p, NULL, re->ng->nexthop, zvrf->table_id, re->metric, re->distance, false); return 0; diff --git a/zebra/rib.h b/zebra/rib.h index ee1df89c0e..455003c930 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -88,7 +88,7 @@ struct route_entry { struct re_list_item next; /* Nexthop structure (from RIB) */ - struct nexthop_group ng; + struct nexthop_group *ng; /* Nexthop group from FIB (optional) */ struct nexthop_group fib_ng; @@ -527,7 +527,7 @@ static inline struct nexthop_group *rib_active_nhg(struct route_entry *re) if (re->fib_ng.nexthop) return &(re->fib_ng); else - return &(re->ng); + return re->ng; } extern void zebra_vty_init(void); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 43e44cad16..9bc919463b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -627,6 +627,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->nexthop_num = 0; re->uptime = monotime(NULL); re->tag = tag; + re->ng = nexthop_group_new(); for (;;) { struct nexthop *nh = NULL; @@ -722,9 +723,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, zserv_nexthop_num_warn(__func__, (const struct prefix *)&p, re->nexthop_num); - if (re->nexthop_num == 0) + if (re->nexthop_num == 0) { + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); - else + } else rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, re); } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index e61e68b7fe..d207ee4046 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -564,7 +564,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = re->nexthop_active_num; } - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -665,7 +665,8 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, * nexthop we are looking up. Therefore, we will just iterate * over the top chain of nexthops. */ - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = re->ng->nexthop; nexthop; + nexthop = nexthop->next) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) num += zserv_encode_nexthop(s, nexthop); @@ -1422,6 +1423,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re->flags = api.flags; re->uptime = monotime(NULL); re->vrf_id = vrf_id; + re->ng = nexthop_group_new(); + if (api.tableid) re->table = api.tableid; else @@ -1433,6 +1436,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) "%s: received a route without nexthops for prefix %pFX from client %s", __func__, &api.prefix, zebra_route_string(client->proto)); + + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return; } @@ -1531,7 +1536,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) EC_ZEBRA_NEXTHOP_CREATION_FAILED, "%s: Nexthops Specified: %d but we failed to properly create one", __PRETTY_FUNCTION__, api.nexthop_num); - nexthops_free(re->ng.nexthop); + nexthops_free(re->ng->nexthop); + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return; } @@ -1573,7 +1579,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) flog_warn(EC_ZEBRA_RX_SRCDEST_WRONG_AFI, "%s: Received SRC Prefix but afi is not v6", __PRETTY_FUNCTION__); - nexthops_free(re->ng.nexthop); + nexthops_free(re->ng->nexthop); + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return; } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index bf343e06e5..31fcba083f 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1419,7 +1419,7 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, ctx->u.rinfo.zd_safi = info->safi; /* Copy nexthops; recursive info is included too */ - copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng.nexthop, NULL); + copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng->nexthop, NULL); /* Ensure that the dplane's nexthops flags are clear. */ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) @@ -1577,7 +1577,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, if (re) copy_nexthops(&(ctx->u.pw.nhg.nexthop), - re->ng.nexthop, NULL); + re->ng->nexthop, NULL); route_unlock_node(rn); } diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index f347d3955c..b54d8fbc12 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -314,7 +314,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, ri->rtm_type = RTN_UNICAST; ri->metric = &re->metric; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (ri->num_nhs >= zrouter.multipath_num) break; diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index 3054b8a34d..a11517ab8b 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -173,7 +173,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, * Figure out the set of nexthops to be added to the message. */ num_nhs = 0; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (num_nhs >= zrouter.multipath_num) break; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 8088ec1bfe..6e0c0b8d88 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -185,7 +185,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, * the label advertised by the recursive nexthop (plus we don't have the * logic yet to push multiple labels). */ - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { /* Skip inactive and recursive entries. */ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -635,7 +635,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe, || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) continue; - for (match_nh = match->ng.nexthop; match_nh; + for (match_nh = match->ng->nexthop; match_nh; match_nh = match_nh->next) { if (match->type == ZEBRA_ROUTE_CONNECT || nexthop->ifindex == match_nh->ifindex) { @@ -686,10 +686,10 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, break; } - if (!match || !match->ng.nexthop) + if (!match || !match->ng->nexthop) return 0; - nexthop->ifindex = match->ng.nexthop->ifindex; + nexthop->ifindex = match->ng->nexthop->ifindex; return 1; } @@ -2611,7 +2611,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, return -1; found = false; - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -2889,7 +2889,7 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, for (rn = route_top(table); rn; rn = route_next(rn)) { update = 0; RNODE_FOREACH_RE (rn, re) { - for (nexthop = re->ng.nexthop; nexthop; + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { if (nexthop->nh_label_type != lsp_type) continue; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 772227a46b..407e29f8c3 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -164,7 +164,7 @@ void zebra_nhg_release(afi_t afi, struct route_entry *re) lookup.vrf_id = re->vrf_id; lookup.afi = afi; - lookup.nhg = re->ng; + lookup.nhg = *re->ng; nhe = hash_lookup(zrouter.nhgs, &lookup); nhe->refcnt--; @@ -446,7 +446,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ - newhop = match->ng.nexthop; + newhop = match->ng->nexthop; if (newhop) { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV6) @@ -455,7 +455,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return 1; } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; - for (ALL_NEXTHOPS(match->ng, newhop)) { + for (ALL_NEXTHOPS_PTR(match->ng, newhop)) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; @@ -475,7 +475,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; - for (ALL_NEXTHOPS(match->ng, newhop)) { + for (ALL_NEXTHOPS_PTR(match->ng, newhop)) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; @@ -660,7 +660,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) re->nexthop_active_num = 0; UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { /* No protocol daemon provides src and so we're skipping * tracking it */ prev_src = nexthop->rmap_src; diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 09edbc9a68..3f1567a95b 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -259,7 +259,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw) * Need to ensure that there's a label binding for all nexthops. * Otherwise, ECMP for this route could render the pseudowire unusable. */ - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (!nexthop->nh_label) { if (IS_ZEBRA_DEBUG_PW) zlog_debug("%s: unlabeled route for %s", diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f385a2d752..c8ba3f9e9d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -196,7 +196,7 @@ int zebra_check_addr(const struct prefix *p) /* Add nexthop to the end of a rib node's nexthop list */ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) { - _nexthop_group_add_sorted(&re->ng, nexthop); + _nexthop_group_add_sorted(re->ng, nexthop); re->nexthop_num++; } @@ -206,8 +206,8 @@ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) */ void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh) { - assert(!re->ng.nexthop); - copy_nexthops(&re->ng.nexthop, nh, NULL); + assert(!re->ng->nexthop); + copy_nexthops(&re->ng->nexthop, nh, NULL); for (struct nexthop *nexthop = nh; nexthop; nexthop = nexthop->next) re->nexthop_num++; } @@ -220,7 +220,7 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop) if (nexthop->prev) nexthop->prev->next = nexthop->next; else - re->ng.nexthop = nexthop->next; + re->ng->nexthop = nexthop->next; re->nexthop_num--; } @@ -505,7 +505,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re) if (re->type != ZEBRA_ROUTE_BGP) return 0; - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) if (!nexthop->nh_label || !nexthop->nh_label->num_labels) return 0; @@ -529,15 +529,15 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } else { struct nexthop *prev; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE); - for (ALL_NEXTHOPS(re->ng, prev)) { + for (ALL_NEXTHOPS_PTR(re->ng, prev)) { if (prev == nexthop) break; if (nexthop_same_firsthop(nexthop, prev)) { @@ -586,7 +586,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, if (!RIB_SYSTEM_ROUTE(old)) { /* Clear old route's FIB flags */ - for (ALL_NEXTHOPS(old->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(old->ng, nexthop)) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -624,7 +624,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) if (info->safi != SAFI_UNICAST) { UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -684,7 +684,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) re->fib_ng.nexthop = NULL; } - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -860,7 +860,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, /* Update real nexthop. This may actually determine if nexthop is active * or not. */ - if (!nexthop_group_active_nexthop_num(&new->ng)) { + if (!nexthop_group_active_nexthop_num(new->ng)) { UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); return; } @@ -929,7 +929,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update the nexthop; we could determine here that nexthop is * inactive. */ - if (nexthop_group_active_nexthop_num(&new->ng)) + if (nexthop_group_active_nexthop_num(new->ng)) nh_active = 1; /* If nexthop is active, install the selected route, if @@ -1047,7 +1047,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, /* both are connected. are either loop or vrf? */ struct nexthop *nexthop = NULL; - for (ALL_NEXTHOPS(alternate->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(alternate->ng, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, alternate->vrf_id); @@ -1055,7 +1055,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return alternate; } - for (ALL_NEXTHOPS(current->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(current->ng, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, current->vrf_id); @@ -1380,7 +1380,7 @@ static void zebra_rib_fixup_system(struct route_node *rn) SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); - for (ALL_NEXTHOPS(re->ng, nhop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nhop)) { if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1532,7 +1532,7 @@ static bool rib_update_re_from_ctx(struct route_entry *re, * that is actually installed. */ matched = true; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -2418,7 +2418,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) info = srcdest_rnode_table_info(rn); zebra_nhg_release(info->afi, re); - nexthops_free(re->ng.nexthop); + nexthops_free(re->ng->nexthop); + nexthop_group_delete(&re->ng); nexthops_free(re->fib_ng.nexthop); XFREE(MTYPE_RE, re); @@ -2486,7 +2487,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, re->nexthop_num, re->nexthop_active_num); - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -2650,6 +2651,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { + nexthops_free(re->ng->nexthop); + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return 0; } @@ -2659,7 +2662,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - zebra_nhg_find(afi, &re->ng, re); + zebra_nhg_find(afi, re->ng, re); /* Set default distance by route type. */ if (re->distance == 0) re->distance = route_distance(re->type); @@ -2795,7 +2798,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop) + if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng->nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; @@ -2808,7 +2811,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, same = re; break; } - for (ALL_NEXTHOPS(re->ng, rtnh)) + for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) /* * No guarantee all kernel send nh with labels * on delete. @@ -2849,7 +2852,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (allow_delete) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ - for (rtnh = fib->ng.nexthop; rtnh; + for (rtnh = fib->ng->nexthop; rtnh; rtnh = rtnh->next) UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); @@ -2905,7 +2908,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; - for (ALL_NEXTHOPS(re->ng, tmp_nh)) { + for (ALL_NEXTHOPS_PTR(re->ng, tmp_nh)) { struct ipaddr vtep_ip; memset(&vtep_ip, 0, sizeof(struct ipaddr)); @@ -2959,6 +2962,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->nexthop_num = 0; re->uptime = monotime(NULL); re->tag = tag; + re->ng = nexthop_group_new(); /* Add nexthop. */ nexthop = nexthop_new(); @@ -3223,7 +3227,7 @@ void rib_sweep_table(struct route_table *table) * this decision needs to be revisited */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); rib_uninstall_kernel(rn, re); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 5df5d94f4b..1494e3bed3 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -384,7 +384,7 @@ static void zebra_rnh_clear_nexthop_rnh_filters(struct route_entry *re) struct nexthop *nexthop; if (re) { - for (nexthop = re->ng.nexthop; nexthop; + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED); } @@ -403,7 +403,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf, route_map_result_t ret; if (prn && re) { - for (nexthop = re->ng.nexthop; nexthop; + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { ret = zebra_nht_route_map_check( afi, proto, &prn->p, zvrf, re, nexthop); @@ -688,7 +688,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, /* Just being SELECTED isn't quite enough - must * have an installed nexthop to be useful. */ - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (rnh_nexthop_valid(re, nexthop)) break; } @@ -707,7 +707,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, break; if (re->type == ZEBRA_ROUTE_NHRP) { - for (nexthop = re->ng.nexthop; nexthop; + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) if (nexthop->type == NEXTHOP_TYPE_IFINDEX) @@ -940,7 +940,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, return; /* free RE and nexthops */ - nexthops_free(re->ng.nexthop); + nexthops_free(re->ng->nexthop); + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); } @@ -963,8 +964,9 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->metric = re->metric; state->vrf_id = re->vrf_id; state->status = re->status; + state->ng = nexthop_group_new(); - route_entry_copy_nexthops(state, re->ng.nexthop); + route_entry_copy_nexthops(state, re->ng->nexthop); rnh->state = state; } @@ -985,7 +987,7 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if (r1->nexthop_num != r2->nexthop_num) return 1; - if (nexthop_group_hash(&r1->ng) != nexthop_group_hash(&r2->ng)) + if (nexthop_group_hash(r1->ng) != nexthop_group_hash(r2->ng)) return 1; return 0; @@ -1035,7 +1037,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, num = 0; nump = stream_get_endp(s); stream_putc(s, 0); - for (ALL_NEXTHOPS(re->ng, nh)) + for (ALL_NEXTHOPS_PTR(re->ng, nh)) if (rnh_nexthop_valid(re, nh)) { stream_putl(s, nh->vrf_id); stream_putc(s, nh->type); @@ -1135,7 +1137,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) if (rnh->state) { vty_out(vty, " resolved via %s\n", zebra_route_string(rnh->state->type)); - for (nexthop = rnh->state->ng.nexthop; nexthop; + for (nexthop = rnh->state->ng->nexthop; nexthop; nexthop = nexthop->next) print_nh(nexthop, vty); } else diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index d9e8c6f968..32375e0a00 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -259,7 +259,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, tm->tm_hour); vty_out(vty, " ago\n"); - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { char addrstr[32]; vty_out(vty, " %c%s", @@ -409,7 +409,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (is_fib) nhg = rib_active_nhg(re); else - nhg = &(re->ng); + nhg = re->ng; if (json) { json_route = json_object_new_object(); @@ -1615,7 +1615,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, fib_cnt[ZEBRA_ROUTE_TOTAL]++; fib_cnt[re->type]++; } - for (nexthop = re->ng.nexthop; (!cnt && nexthop); + for (nexthop = re->ng->nexthop; (!cnt && nexthop); nexthop = nexthop->next) { cnt++; rib_cnt[ZEBRA_ROUTE_TOTAL]++; -- cgit v1.2.3 From eecacedc3b9526b59ef690bce41f41158a137c9f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 15 Feb 2019 11:16:22 -0500 Subject: zebra: Remove re->nexthop_num from re The nexthop_num is not a function of the re. It is owned by the nexthop group. Signed-off-by: Donald Sharp --- zebra/redistribute.c | 1 - zebra/rib.h | 1 - zebra/rt_netlink.c | 11 +++++------ zebra/zebra_rib.c | 7 +------ zebra/zebra_rnh.c | 3 ++- 5 files changed, 8 insertions(+), 15 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 65b62679e8..42f8c812b4 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -676,7 +676,6 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, newre->metric = re->metric; newre->mtu = re->mtu; newre->table = zvrf->table_id; - newre->nexthop_num = 0; newre->uptime = monotime(NULL); newre->instance = re->table; newre->ng = nexthop_group_new(); diff --git a/zebra/rib.h b/zebra/rib.h index 455003c930..4bef6e0543 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -136,7 +136,6 @@ struct route_entry { #define ROUTE_ENTRY_FAILED 0x20 /* Nexthop information. */ - uint8_t nexthop_num; uint8_t nexthop_active_num; /* Sequence value incremented for each dataplane operation */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 9bc919463b..b36fbb2008 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -609,7 +609,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, &src_p, &nh, table, metric, mtu, distance, tag); } else { /* This is a multipath route */ - + uint8_t nhop_num; struct route_entry *re; struct rtnexthop *rtnh = (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); @@ -624,7 +624,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->mtu = mtu; re->vrf_id = vrf_id; re->table = table; - re->nexthop_num = 0; re->uptime = monotime(NULL); re->tag = tag; re->ng = nexthop_group_new(); @@ -720,10 +719,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, rtnh = RTNH_NEXT(rtnh); } - zserv_nexthop_num_warn(__func__, - (const struct prefix *)&p, - re->nexthop_num); - if (re->nexthop_num == 0) { + nhop_num = nexthop_group_nexthop_num(re->ng); + zserv_nexthop_num_warn( + __func__, (const struct prefix *)&p, nhop_num); + if (nhop_num == 0) { nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); } else diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c8ba3f9e9d..c56c953618 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -197,7 +197,6 @@ int zebra_check_addr(const struct prefix *p) void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) { _nexthop_group_add_sorted(re->ng, nexthop); - re->nexthop_num++; } @@ -208,8 +207,6 @@ void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh) { assert(!re->ng->nexthop); copy_nexthops(&re->ng->nexthop, nh, NULL); - for (struct nexthop *nexthop = nh; nexthop; nexthop = nexthop->next) - re->nexthop_num++; } /* Delete specified nexthop from the list. */ @@ -221,7 +218,6 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop) nexthop->prev->next = nexthop->next; else re->ng->nexthop = nexthop->next; - re->nexthop_num--; } @@ -2485,7 +2481,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", straddr, re->metric, re->mtu, re->distance, re->flags, re->status); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, - re->nexthop_num, re->nexthop_active_num); + nexthop_group_nexthop_num(re->ng), re->nexthop_active_num); for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { struct interface *ifp; @@ -2959,7 +2955,6 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->mtu = mtu; re->table = table_id; re->vrf_id = vrf_id; - re->nexthop_num = 0; re->uptime = monotime(NULL); re->tag = tag; re->ng = nexthop_group_new(); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 1494e3bed3..af3c1b818f 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -984,7 +984,8 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if (r1->metric != r2->metric) return 1; - if (r1->nexthop_num != r2->nexthop_num) + if (nexthop_group_nexthop_num(r1->ng) + != nexthop_group_nexthop_num(r2->ng)) return 1; if (nexthop_group_hash(r1->ng) != nexthop_group_hash(r2->ng)) -- cgit v1.2.3 From 9a0d4dd39be7cbed048e45b5a27ceb81608d76f6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 15 Feb 2019 11:39:12 -0500 Subject: zebra: Remove nexthop_active_num from route entry The nexthop_active_num data structure is a property of the nexthop group. Move the keeping of this data to that. Signed-off-by: Donald Sharp --- zebra/rib.h | 3 --- zebra/zapi_msg.c | 13 +++++++------ zebra/zebra_fpm_dt.c | 2 +- zebra/zebra_nhg.c | 16 +++++++++------- zebra/zebra_rib.c | 3 ++- 5 files changed, 19 insertions(+), 18 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rib.h b/zebra/rib.h index 4bef6e0543..5b5bd4c279 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -135,9 +135,6 @@ struct route_entry { /* Route has Failed installation into the Data Plane in some manner */ #define ROUTE_ENTRY_FAILED 0x20 - /* Nexthop information. */ - uint8_t nexthop_active_num; - /* Sequence value incremented for each dataplane operation */ uint32_t dplane_sequence; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d207ee4046..ecbf39dda0 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -522,7 +522,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct zapi_route api; struct zapi_nexthop *api_nh; struct nexthop *nexthop; - int count = 0; + uint8_t count = 0; afi_t afi; size_t stream_size = MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route)); @@ -559,11 +559,6 @@ int zsend_redistribute_route(int cmd, struct zserv *client, memcpy(&api.src_prefix, src_p, sizeof(api.src_prefix)); } - /* Nexthops. */ - if (re->nexthop_active_num) { - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = re->nexthop_active_num; - } for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -595,6 +590,12 @@ int zsend_redistribute_route(int cmd, struct zserv *client, count++; } + /* Nexthops. */ + if (count) { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = count; + } + /* Attributes. */ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); api.distance = re->distance; diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index e87fa0ad71..debcf60ee5 100644 --- a/zebra/zebra_fpm_dt.c +++ b/zebra/zebra_fpm_dt.c @@ -90,7 +90,7 @@ static int zfpm_dt_find_route(rib_dest_t **dest_p, struct route_entry **re_p) if (!re) continue; - if (re->nexthop_active_num <= 0) + if (nexthop_group_active_nexthop_num(re->ng) == 0) continue; *dest_p = dest; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 407e29f8c3..569bc6e5ec 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -644,9 +644,8 @@ static unsigned nexthop_active_check(struct route_node *rn, /* * Iterate over all nexthops of the given RIB entry and refresh their - * ACTIVE flag. re->nexthop_active_num is updated accordingly. If any - * nexthop is found to toggle the ACTIVE flag, the whole re structure - * is flagged with ROUTE_ENTRY_CHANGED. + * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag, + * the whole re structure is flagged with ROUTE_ENTRY_CHANGED. * * Return value is the new number of active nexthops. */ @@ -656,8 +655,8 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) union g_addr prev_src; unsigned int prev_active, new_active; ifindex_t prev_index; + uint8_t curr_active = 0; - re->nexthop_active_num = 0; UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { @@ -674,12 +673,15 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) */ new_active = nexthop_active_check(rn, re, nexthop); if (new_active - && re->nexthop_active_num >= zrouter.multipath_num) { + && nexthop_group_active_nexthop_num(re->ng) + >= zrouter.multipath_num) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); new_active = 0; } + if (new_active) - re->nexthop_active_num++; + curr_active++; + /* Don't allow src setting on IPv6 addr for now */ if (prev_active != new_active || prev_index != nexthop->ifindex || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX @@ -694,5 +696,5 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); } - return re->nexthop_active_num; + return curr_active; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c56c953618..d3c6f5ba11 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2481,7 +2481,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", straddr, re->metric, re->mtu, re->distance, re->flags, re->status); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, - nexthop_group_nexthop_num(re->ng), re->nexthop_active_num); + nexthop_group_nexthop_num(re->ng), + nexthop_group_active_nexthop_num(re->ng)); for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { struct interface *ifp; -- cgit v1.2.3 From 8b5bdc8bdfdb95d5e22ccb8733dbd35c84f3f79d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 25 Feb 2019 17:59:28 -0500 Subject: zebra: Remove afi field in nexthop hash entry I do not believe we should be hashing based on AFI in for our upper level nexthop group entries. These should be ambiguous with regards to address families since an ipv4 or ipv6 address can have the same interface nexthop. This can be seen in NEXTHOP_TYPE_IFINDEX. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 14 ++++---------- zebra/zebra_nhg.h | 10 ++++------ zebra/zebra_rib.c | 5 ++--- zebra/zebra_vty.c | 18 ++++++------------ 4 files changed, 16 insertions(+), 31 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1839133310..172212c652 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -45,7 +45,6 @@ static void *zebra_nhg_alloc(void *arg) nhe = XMALLOC(MTYPE_TMP, sizeof(struct nhg_hash_entry)); nhe->vrf_id = copy->vrf_id; - nhe->afi = copy->afi; nhe->refcnt = 0; nhe->dplane_ref = zebra_router_get_next_sequence(); nhe->nhg.nexthop = NULL; @@ -68,6 +67,7 @@ static uint32_t zebra_nhg_hash_key_nexthop_group(struct nexthop_group *nhg) * resolved nexthops */ for (nh = nhg->nexthop; nh; nh = nh->next) { + key = jhash_1word(nh->type, key); key = jhash_2words(nh->vrf_id, nh->nh_label_type, key); /* gate and blackhole are together in a union */ key = jhash(&nh->gate, sizeof(nh->gate), key); @@ -97,7 +97,7 @@ uint32_t zebra_nhg_hash_key(const void *arg) const struct nhg_hash_entry *nhe = arg; int key = 0x5a351234; - key = jhash_2words(nhe->vrf_id, nhe->afi, key); + key = jhash_1word(nhe->vrf_id, key); return jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); } @@ -127,9 +127,6 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->vrf_id != nhe2->vrf_id) return false; - if (nhe1->afi != nhe2->afi) - return false; - /* * Again we are not interested in looking at any recursively * resolved nexthops. Top level only @@ -183,25 +180,22 @@ void zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) zebra_nhg_lookup_get(zrouter.nhgs_id, &lookup); } -void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, - struct route_entry *re) +void zebra_nhg_find(struct nexthop_group *nhg, struct route_entry *re) { struct nhg_hash_entry lookup; memset(&lookup, 0, sizeof(lookup)); lookup.vrf_id = re->vrf_id; - lookup.afi = afi; lookup.nhg = *nhg; re->nhe = zebra_nhg_lookup_get(zrouter.nhgs, &lookup); } -void zebra_nhg_release(afi_t afi, struct route_entry *re) +void zebra_nhg_release(struct route_entry *re) { struct nhg_hash_entry lookup, *nhe; lookup.vrf_id = re->vrf_id; - lookup.afi = afi; lookup.nhg = *re->ng; nhe = hash_lookup(zrouter.nhgs, &lookup); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index e93b579560..227e87256d 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -26,11 +26,8 @@ #include "zebra/rib.h" #include "lib/nexthop_group.h" -extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); - struct nhg_hash_entry { uint32_t id; - afi_t afi; vrf_id_t vrf_id; struct nexthop_group nhg; @@ -63,8 +60,9 @@ extern uint32_t zebra_nhg_id_key(const void *arg); extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); extern bool zebra_nhg_id_equal(const void *arg1, const void *arg2); -extern void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, - struct route_entry *re); +extern void zebra_nhg_find(struct nexthop_group *nhg, struct route_entry *re); extern void zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg); -void zebra_nhg_release(afi_t afi, struct route_entry *re); +void zebra_nhg_release(struct route_entry *re); + +extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d3c6f5ba11..c8684c1a93 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2411,8 +2411,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - info = srcdest_rnode_table_info(rn); - zebra_nhg_release(info->afi, re); + zebra_nhg_release(re); nexthops_free(re->ng->nexthop); nexthop_group_delete(&re->ng); @@ -2659,7 +2658,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - zebra_nhg_find(afi, re->ng, re); + zebra_nhg_find(re->ng, re); /* Set default distance by route type. */ if (re->distance == 0) re->distance = route_distance(re->type); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 32375e0a00..b0b888381c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1103,7 +1103,7 @@ DEFUN (ip_nht_default_route, } static void show_nexthop_group_cmd_helper(struct vty *vty, - struct zebra_vrf *zvrf, afi_t afi) + struct zebra_vrf *zvrf) { struct list *list = hash_to_list(zrouter.nhgs); struct nhg_hash_entry *nhe; @@ -1112,15 +1112,12 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) { struct nexthop *nhop; - if (nhe->afi != afi) - continue; - if (nhe->vrf_id != zvrf->vrf->vrf_id) continue; vty_out(vty, - "Group: %u RefCnt: %u afi: %d Valid: %d Installed: %d\n", - nhe->dplane_ref, nhe->refcnt, nhe->afi, + "Group: %u ID: %u RefCnt: %d Valid: %d Installed: %d\n", + nhe->dplane_ref, nhe->id, nhe->refcnt, nhe->flags & NEXTHOP_GROUP_VALID, nhe->flags & NEXTHOP_GROUP_INSTALLED); @@ -1135,14 +1132,11 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, DEFPY (show_nexthop_group, show_nexthop_group_cmd, - "show nexthop-group [vrf ]", + "show nexthop-group [vrf ]", SHOW_STR - IP_STR - IP6_STR "Show Nexthop Groups\n" VRF_FULL_CMD_HELP_STR) { - afi_t afi = v4 ? AFI_IP : AFI_IP6; struct zebra_vrf *zvrf; if (vrf_all) { @@ -1156,7 +1150,7 @@ DEFPY (show_nexthop_group, continue; vty_out(vty, "VRF: %s\n", vrf->name); - show_nexthop_group_cmd_helper(vty, zvrf, afi); + show_nexthop_group_cmd_helper(vty, zvrf); } return CMD_SUCCESS; @@ -1172,7 +1166,7 @@ DEFPY (show_nexthop_group, return CMD_SUCCESS; } - show_nexthop_group_cmd_helper(vty, zvrf, afi); + show_nexthop_group_cmd_helper(vty, zvrf); return CMD_SUCCESS; } -- cgit v1.2.3 From d9f5b2f50f53d625986dbd47cd12778c9f841f0c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 25 Feb 2019 18:18:07 -0500 Subject: zebra: Add functionality to parse RTM_NEWNEXTHOP and RTM_DELNEXTHOP messages Add the functionality to parse new nexthop group messages from the kernel and insert them into the appropriate hash tables. Parsing is done at startup between interface and interface address lookup. Add functionality to parse changes to nexthops we already have. Add functionality to parse delete nexthop messages from the kernel and remove them from our table. Signed-off-by: Stephen Worley --- zebra/if_netlink.c | 6 ++ zebra/kernel_netlink.c | 8 +- zebra/rt_netlink.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++++ zebra/rt_netlink.h | 4 + zebra/zebra_errors.c | 9 ++ zebra/zebra_errors.h | 1 + zebra/zebra_nhg.c | 201 ++++++++++++++++++++++++++-------- zebra/zebra_nhg.h | 16 ++- zebra/zebra_rib.c | 6 +- zebra/zebra_router.c | 10 +- 10 files changed, 490 insertions(+), 59 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index b402cc4965..52d91007b4 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -66,6 +66,7 @@ #include "zebra/zebra_ptm.h" #include "zebra/zebra_mpls.h" #include "zebra/kernel_netlink.h" +#include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_vxlan.h" @@ -1477,6 +1478,11 @@ int netlink_protodown(struct interface *ifp, bool down) void interface_list(struct zebra_ns *zns) { interface_lookup_netlink(zns); + /* We add routes for interface address, + * so we need to get the nexthop info + * from the kernel before we can do that + */ + netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 7889c70cff..a81788028e 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -295,13 +295,9 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELRULE: return netlink_rule_change(h, ns_id, startup); case RTM_NEWNEXTHOP: + return netlink_nexthop_change(h, ns_id, startup); case RTM_DELNEXTHOP: - case RTM_GETNEXTHOP: - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Got a nexthop: %s(%d) message!", - nl_msg_type_to_str(h->nlmsg_type), - h->nlmsg_type); - break; + return netlink_nexthop_change(h, ns_id, startup); default: /* * If we have received this message then diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b36fbb2008..b30805b982 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Hack for GNU libc version 2. */ #ifndef MSG_TRUNC @@ -62,6 +63,7 @@ #include "zebra/zebra_mpls.h" #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" +#include "zebra/zebra_nhg.h" #include "zebra/zebra_mroute.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" @@ -1920,6 +1922,292 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } +/** + * netlink_nexthop_process_nh() - Parse the gatway/if info from a new nexthop + * + * @tb: Netlink RTA data + * @family: Address family in the nhmsg + * @ns_id: Namspace id + * + * Return: New nexthop + */ +static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, + unsigned char family, + ns_id_t ns_id) +{ + struct nexthop nh = {0}; + void *gate = NULL; + struct interface *ifp = NULL; + int if_index; + size_t sz; + + if_index = *(int *)RTA_DATA(tb[NHA_OIF]); + + if (tb[NHA_GATEWAY]) { + switch (family) { + case AF_INET: + nh.type = NEXTHOP_TYPE_IPV4_IFINDEX; + sz = 4; + break; + case AF_INET6: + nh.type = NEXTHOP_TYPE_IPV6_IFINDEX; + sz = 16; + break; + default: + flog_warn( + EC_ZEBRA_BAD_NHG_MESSAGE, + "Nexthop with bad address family (%d) received from kernel", + family); + // TODO: Different return value? + return nh; + } + gate = RTA_DATA(tb[NHA_GATEWAY]); + memcpy(&(nh.gate), gate, sz); + } else { + nh.type = NEXTHOP_TYPE_IFINDEX; + } + + nh.ifindex = if_index; + + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex); + if (ifp) { + nh.vrf_id = ifp->vrf_id; + } else { + flog_warn( + EC_ZEBRA_UNKNOWN_INTERFACE, + "%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT", + __PRETTY_FUNCTION__, nh.ifindex); + + nh.vrf_id = VRF_DEFAULT; + } + + if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) { + uint16_t encap_type = *(uint16_t *)RTA_DATA(tb[NHA_ENCAP_TYPE]); + int num_labels = 0; + mpls_label_t labels[MPLS_MAX_LABELS] = {0}; + + if (encap_type == LWTUNNEL_ENCAP_MPLS) { + num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels); + } + + if (num_labels) { + nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, + labels); + } + } + + return nh; +} + +/** + * netlink_nexthop_process_group() - Iterate over nhmsg nexthop group + * + * @tb: Netlink RTA data + * + * Return: TODO: Not sure yet + */ +static int netlink_nexthop_process_group(struct rtattr **tb) +{ + int count; + struct nexthop_grp *n_grp = NULL; + + n_grp = RTA_DATA(tb[NHA_GROUP]); + count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp)); + + if (!count || (count * sizeof(*n_grp)) != RTA_PAYLOAD(tb[NHA_GROUP])) { + flog_warn(EC_ZEBRA_BAD_NHG_MESSAGE, + "Invalid nexthop group received from the kernel"); + return -1; + } + + // TODO: Need type for something? + // zlog_debug("group type: %d", + // *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); + + + for (int i = 0; i < count; i++) { + // TODO: Lookup by id and if we already have entries + // for that id, delete it? + + /* We do not care about nexthop_grp.weight at + * this time. But we should figure out + * how to adapt this to our code in + * the future. + */ + } + + return count; +} + +/** + * netlink_nexthop_change() - Read in change about nexthops from the kernel + * + * @h: Netlink message header + * @ns_id: Namspace id + * @startup: Are we reading under startup conditions? + * + * Return: Result status + */ +int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + int len; + /* nexthop group id */ + uint32_t id; + unsigned char family; + struct nhmsg *nhm = NULL; + /* struct for nexthop group abstraction */ + struct nexthop_group nhg = {0}; + /* zebra's version of nexthops */ + struct nexthop nh = {0}; + /* struct that goes into our tables */ + struct nhg_hash_entry *nhe = NULL; + struct rtattr *tb[NHA_MAX + 1]; + + + nhm = NLMSG_DATA(h); + + if (startup && h->nlmsg_type != RTM_NEWNEXTHOP) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct nhmsg)); + if (len < 0) { + zlog_warn( + "%s: Message received from netlink is of a broken size %d %zu", + __PRETTY_FUNCTION__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct nhmsg))); + return -1; + } + + memset(tb, 0, sizeof(tb)); + netlink_parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len); + + + if (!tb[NHA_ID]) { + flog_warn( + EC_ZEBRA_BAD_NHG_MESSAGE, + "Nexthop group without an ID received from the kernel"); + return -1; + } + + /* We use the ID key'd nhg table for kernel updates */ + id = *((uint32_t *)RTA_DATA(tb[NHA_ID])); + family = nhm->nh_family; + + if (IS_ZEBRA_DEBUG_KERNEL) { + zlog_debug("Nexthop ID (%u) update from the kernel", id); + } + + /* Lookup via the id */ + nhe = zebra_nhg_lookup_id(id); + + if (h->nlmsg_type == RTM_NEWNEXTHOP) { + if (tb[NHA_GROUP]) { + /** + * If this is a group message its only going to have + * an array of nexthop IDs associated with it + */ + return -1; + netlink_nexthop_process_group(tb); + } else if (tb[NHA_BLACKHOLE]) { + /** + * This nexthop is just for blackhole-ing traffic, + * it should not have an OIF, GATEWAY, or ENCAP + */ + nh.type = NEXTHOP_TYPE_BLACKHOLE; + // TODO: Handle blackhole case + nh.bh_type = BLACKHOLE_UNSPEC; + } else if (tb[NHA_OIF]) { + /** + * This is a true new nexthop, so we need + * to parse the gateway and device info + */ + nh = netlink_nexthop_process_nh(tb, family, ns_id); + } + + + nexthop_group_add_sorted(&nhg, &nh); + + if (nhe) { + /* This is a change to a group we already have */ + nexthops_free(nhe->nhg.nexthop); + nhe->nhg.nexthop = NULL; + nexthop_group_copy(&nhe->nhg, &nhg); + } else { + /* This is a new nexthop group */ + nhe = zebra_nhg_find(&nhg, nh.vrf_id, id); + if (nhe) { + nhe->is_kernel_nh = true; + } else { + return -1; + } + } + } else if (h->nlmsg_type == RTM_DELNEXTHOP) { + if (!nhe) { + flog_warn( + EC_ZEBRA_BAD_NHG_MESSAGE, + "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table", + id); + return -1; + } + + // TODO: Run some active check on all route_entry's? + zebra_nhg_release(nhe); + } + + + return 0; +} + +/** + * netlink_request_nexthop() - Request nextop information from the kernel + * @zns: Zebra namespace + * @family: AF_* netlink family + * @type: RTM_* route type + * + * Return: Result status + */ +static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type) +{ + struct { + struct nlmsghdr n; + struct nhmsg nhm; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); + req.nhm.nh_family = family; + + return netlink_request(&zns->netlink_cmd, &req.n); +} + +/** + * netlink_nexthop_read() - Nexthop read function using netlink interface + * + * @zns: Zebra name space + * + * Return: Result status + * Only called at bootstrap time. + */ +int netlink_nexthop_read(struct zebra_ns *zns) +{ + int ret; + struct zebra_dplane_info dp_info; + + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); + + /* Get nexthop objects */ + ret = netlink_request_nexthop(zns, AF_UNSPEC, RTM_GETNEXTHOP); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd, + &dp_info, 0, 1); + return 0; +} + + int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, int llalen, ns_id_t ns_id) { diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 29e0152bb2..2b4b145149 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -69,6 +69,10 @@ extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx); extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_route_read(struct zebra_ns *zns); +extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, + int startup); +extern int netlink_nexthop_read(struct zebra_ns *zns); + extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id); extern int netlink_macfdb_read(struct zebra_ns *zns); extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index e14f1ee58c..4f97f3669f 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -292,6 +292,15 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Check to see if the entry already exists or if the netlink message was parsed incorrectly." }, + { + .code = EC_ZEBRA_NHG_SYNC, + .title = + "Zebra's Nexthop Groups are out of sync", + .description = + "Zebra's nexthop group tables are out of sync with the nexthop groups in the fib.", + .suggestion = + "Check the current status of the kernels nexthop groups and compare it to Zebra's." + }, /* Warnings */ { .code = EC_ZEBRAING_LM_PROTO_MISMATCH, diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 44d61fc9b0..73bb53a773 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -73,6 +73,7 @@ enum zebra_log_refs { EC_ZEBRA_VTEP_ADD_FAILED, EC_ZEBRA_VNI_ADD_FAILED, EC_ZEBRA_NHG_TABLE_INSERT_FAILED, + EC_ZEBRA_NHG_SYNC, /* warnings */ EC_ZEBRA_NS_NOTIFY_READ, EC_ZEBRAING_LM_PROTO_MISMATCH, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 172212c652..89f6691dab 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -35,23 +35,86 @@ #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" #include "zebra/rt.h" +#include "zebra_errors.h" + +/** + * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table + * + * @id: ID to look for + * + * Return: Nexthop hash entry if found/NULL if not found + */ +struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id) +{ + struct nhg_hash_entry lookup = {0}; + + lookup.id = id; + return hash_lookup(zrouter.nhgs_id, &lookup); +} + +/** + * zebra_nhg_insert_id() - Insert a nhe into the id hashed table + * + * @nhe: The entry directly from the other table + * + * Return: Result status + */ +int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) +{ + if (hash_lookup(zrouter.nhgs_id, nhe)) { + flog_err( + EC_ZEBRA_NHG_TABLE_INSERT_FAILED, + "Failed inserting NHG id=%u into the ID hash table, entry already exists", + nhe->id); + return -1; + } + + hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern); + + return 0; +} static void *zebra_nhg_alloc(void *arg) { + /* lock for getiing and setting the id */ + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + /* id counter to keep in sync with kernel */ + static uint32_t id_counter = 0; struct nhg_hash_entry *nhe; struct nhg_hash_entry *copy = arg; - nhe = XMALLOC(MTYPE_TMP, sizeof(struct nhg_hash_entry)); + nhe = XCALLOC(MTYPE_TMP, sizeof(struct nhg_hash_entry)); + + pthread_mutex_lock(&lock); /* Lock, set the id counter from kernel */ + if (copy->id) { + /* This is from the kernel if it has an id */ + if (copy->id > id_counter) { + /* Increase our counter so we don't try to create + * an ID that already exists + */ + id_counter = copy->id; + } + nhe->id = copy->id; + /* Mark as valid since from the kernel */ + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + } else { + nhe->id = ++id_counter; + } + pthread_mutex_unlock(&lock); nhe->vrf_id = copy->vrf_id; nhe->refcnt = 0; + nhe->is_kernel_nh = false; nhe->dplane_ref = zebra_router_get_next_sequence(); nhe->nhg.nexthop = NULL; nexthop_group_copy(&nhe->nhg, ©->nhg); - nhe->refcnt = 1; + /* Add to id table as well */ + zebra_nhg_insert_id(nhe); + return nhe; } @@ -95,11 +158,15 @@ static uint32_t zebra_nhg_hash_key_nexthop_group(struct nexthop_group *nhg) uint32_t zebra_nhg_hash_key(const void *arg) { const struct nhg_hash_entry *nhe = arg; + int key = 0x5a351234; key = jhash_1word(nhe->vrf_id, key); - return jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); + key = jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); + + + return key; } uint32_t zebra_nhg_id_key(const void *arg) @@ -109,14 +176,6 @@ uint32_t zebra_nhg_id_key(const void *arg) return nhe->id; } -bool zebra_nhg_id_equal(const void *arg1, const void *arg2) -{ - const struct nhg_hash_entry *nhe1 = arg1; - const struct nhg_hash_entry *nhe2 = arg2; - - return (nhe1->id == nhe2->id); -} - bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) { const struct nhg_hash_entry *nhe1 = arg1; @@ -149,60 +208,116 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) return true; } -/** - * Helper function for lookup and get() - * since we are using two different tables. - * - * Avoiding code duplication hopefully. - */ -static struct nhg_hash_entry * -zebra_nhg_lookup_get(struct hash *hash_table, - struct nhg_hash_entry *lookup) +bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) { - struct nhg_hash_entry *nhe; - - nhe = hash_lookup(hash_table, lookup); + const struct nhg_hash_entry *nhe1 = arg1; + const struct nhg_hash_entry *nhe2 = arg2; - if (!nhe) - nhe = hash_get(hash_table, lookup, zebra_nhg_alloc); - else - nhe->refcnt++; + return nhe1->id == nhe2->id; +} - return nhe; +struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) +{ + // TODO: How this will work is yet to be determined + return NULL; } -void zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) +/** + * zebra_nhg_find() - Find the zebra nhg in our table, or create it + * + * @nhg: Nexthop group we lookup with + * @vrf_id: VRF id + * @id: ID we lookup with, 0 means its from us and we need to give it + * an ID, otherwise its from the kernel as we use the ID it gave + * us. + * + * Return: Hash entry found or created + */ +struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, + vrf_id_t vrf_id, uint32_t id) { struct nhg_hash_entry lookup = {0}; + struct nhg_hash_entry *nhe = NULL; + lookup.id = id; + lookup.vrf_id = vrf_id; lookup.nhg = *nhg; - zebra_nhg_lookup_get(zrouter.nhgs_id, &lookup); + + nhe = hash_lookup(zrouter.nhgs, &lookup); + + if (!nhe) { + nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); + } else { + if (id) { + /* Duplicate but with different ID from the kernel */ + + /* The kernel allows duplicate nexthops as long as they + * have different IDs. We are ignoring those to prevent + * syncing problems with the kernel changes. + */ + flog_warn( + EC_ZEBRA_DUPLICATE_NHG_MESSAGE, + "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring", + id); + return NULL; + } + } + + return nhe; } -void zebra_nhg_find(struct nexthop_group *nhg, struct route_entry *re) +/** + * zebra_nhg_free() - Free the nexthop group hash entry + * + * arg: Nexthop group entry to free + */ +void zebra_nhg_free(void *arg) { - struct nhg_hash_entry lookup; + struct nhg_hash_entry *nhe = NULL; - memset(&lookup, 0, sizeof(lookup)); - lookup.vrf_id = re->vrf_id; - lookup.nhg = *nhg; + nhe = (struct nhg_hash_entry *)arg; - re->nhe = zebra_nhg_lookup_get(zrouter.nhgs, &lookup); + nexthops_free(nhe->nhg.nexthop); + XFREE(MTYPE_TMP, nhe); } -void zebra_nhg_release(struct route_entry *re) +/** + * zebra_nhg_release() - Release a nhe from the tables + * + * @nhe: Nexthop group hash entry + */ +void zebra_nhg_release(struct nhg_hash_entry *nhe) { - struct nhg_hash_entry lookup, *nhe; + if (nhe->refcnt) { + flog_err( + EC_ZEBRA_NHG_SYNC, + "Kernel deleted a nexthop group with ID (%u) that we are still using for a route", + nhe->id); + // TODO: Re-send to kernel + } - lookup.vrf_id = re->vrf_id; - lookup.nhg = *re->ng; + hash_release(zrouter.nhgs, nhe); + hash_release(zrouter.nhgs_id, nhe); + zebra_nhg_free(nhe); +} - nhe = hash_lookup(zrouter.nhgs, &lookup); +/** + * zebra_nhg_decrement_ref() - Decrement the reference count, release if unused + * + * @nhe: Nexthop group hash entry + * + * If the counter hits 0 and is not a nexthop group that was created by the + * kernel, we don't need to have it in our table anymore. + */ +void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) +{ nhe->refcnt--; - if (nhe->refcnt == 0) - hash_release(zrouter.nhgs, nhe); + if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { + zebra_nhg_release(nhe); + } + // re->ng = NULL; } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 227e87256d..126f342c54 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -29,6 +29,7 @@ struct nhg_hash_entry { uint32_t id; vrf_id_t vrf_id; + bool is_kernel_nh; struct nexthop_group nhg; @@ -54,15 +55,22 @@ struct nhg_hash_entry { void zebra_nhg_init(void); void zebra_nhg_terminate(void); +extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id); +extern int zebra_nhg_insert_id(struct nhg_hash_entry *nhe); + extern uint32_t zebra_nhg_hash_key(const void *arg); extern uint32_t zebra_nhg_id_key(const void *arg); extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); -extern bool zebra_nhg_id_equal(const void *arg1, const void *arg2); +extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); -extern void zebra_nhg_find(struct nexthop_group *nhg, struct route_entry *re); -extern void zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg); -void zebra_nhg_release(struct route_entry *re); +extern struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, + vrf_id_t vrf_id, uint32_t id); +extern struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, + struct nexthop_group *nhg); +void zebra_nhg_free(void *arg); +void zebra_nhg_release(struct nhg_hash_entry *nhe); +void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c8684c1a93..3b3bf921bc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2411,8 +2411,9 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - zebra_nhg_release(re); + zebra_nhg_decrement_ref(re->nhe); + // TODO: We need to hold on nh's until refcnt is 0 right? nexthops_free(re->ng->nexthop); nexthop_group_delete(&re->ng); nexthops_free(re->fib_ng.nexthop); @@ -2658,7 +2659,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - zebra_nhg_find(re->ng, re); + re->nhe = zebra_nhg_find(re->ng, re->vrf_id, 0); + re->nhe->refcnt++; /* Set default distance by route type. */ if (re->distance == 0) re->distance = route_distance(re->type); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 100d17ecde..408fc16dd1 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -218,6 +218,11 @@ void zebra_router_terminate(void) zebra_vxlan_disable(); zebra_mlag_terminate(); + hash_clean(zrouter.nhgs, zebra_nhg_free); + hash_free(zrouter.nhgs); + hash_clean(zrouter.nhgs_id, NULL); + hash_free(zrouter.nhgs_id); + hash_clean(zrouter.rules_hash, zebra_pbr_rules_free); hash_free(zrouter.rules_hash); @@ -254,13 +259,10 @@ void zebra_router_init(void) zebra_pbr_iptable_hash_equal, "IPtable Hash Entry"); - /* Index via hash and IDs so we can - * easily communicate to/from the kernel - */ zrouter.nhgs = hash_create_size(8, zebra_nhg_hash_key, zebra_nhg_hash_equal, "Zebra Router Nexthop Groups"); zrouter.nhgs_id = - hash_create_size(8, zebra_nhg_id_key, zebra_nhg_id_equal, + hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal, "Zebra Router Nexthop Groups ID index"); } -- cgit v1.2.3 From 8e7663796904f12ab31320d8d5a056da158483fe Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:16:52 -0500 Subject: zebra: Route entries use nexthop entry ID's instead of pointers Switched the route entries to use ID's instead of pointers. Perform lookups with the ID and then check if its null. Signed-off-by: Stephen Worley --- zebra/rib.h | 3 ++- zebra/zebra_rib.c | 14 ++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rib.h b/zebra/rib.h index a95bcc0550..e6d6d87447 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -93,7 +93,8 @@ struct route_entry { /* Nexthop group from FIB (optional) */ struct nexthop_group fib_ng; - struct nhg_hash_entry *nhe; + /* Nexthop group hash entry ID */ + uint32_t nhe_id; /* Tag */ route_tag_t tag; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 3b3bf921bc..5f942a7ecf 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2396,7 +2396,7 @@ static void rib_addnode(struct route_node *rn, void rib_unlink(struct route_node *rn, struct route_entry *re) { rib_dest_t *dest; - rib_table_info_t *info; + struct nhg_hash_entry *nhe = NULL; assert(rn && re); @@ -2411,7 +2411,9 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - zebra_nhg_decrement_ref(re->nhe); + nhe = zebra_nhg_lookup_id(re->nhe_id); + if (nhe) + zebra_nhg_decrement_ref(nhe); // TODO: We need to hold on nh's until refcnt is 0 right? nexthops_free(re->ng->nexthop); @@ -2638,6 +2640,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 = NULL; + struct nhg_hash_entry *nhe = NULL; int ret = 0; if (!re) @@ -2659,8 +2662,11 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - re->nhe = zebra_nhg_find(re->ng, re->vrf_id, 0); - re->nhe->refcnt++; + nhe = zebra_nhg_find(re->ng, re->vrf_id, 0); + + re->nhe_id = nhe->id; + nhe->refcnt++; + /* Set default distance by route type. */ if (re->distance == 0) re->distance = route_distance(re->type); -- cgit v1.2.3 From 9865e1c393ff3c3828a6ff85231c1144e86e03b4 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:26:33 -0500 Subject: zebra: Add calls to the nexthop context process result function Added in case statements to handle finished dataplane contexts and then handle them with the nexthop process result function. Signed-off-by: Stephen Worley --- zebra/zebra_rib.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5f942a7ecf..1ea11640d7 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3424,6 +3424,12 @@ static int rib_process_dplane_results(struct thread *thread) rib_process_dplane_notify(ctx); break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_NH_DELETE: + zebra_nhg_dplane_result(ctx); + break; + case DPLANE_OP_LSP_INSTALL: case DPLANE_OP_LSP_UPDATE: case DPLANE_OP_LSP_DELETE: -- cgit v1.2.3 From 8032b71737520f883abeb1e43476d88cd5a4c304 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 10:55:53 -0400 Subject: zebra: Update rib_add to take a nexthop ID Add a parameter to the rib_add function so that it takes a nexthop ID from the kernel if one is passed along with the route. Signed-off-by: Stephen Worley --- zebra/connected.c | 4 ++-- zebra/kernel_socket.c | 3 ++- zebra/rib.h | 4 ++-- zebra/rt_netlink.c | 3 ++- zebra/rtread_getmsg.c | 2 +- zebra/zebra_rib.c | 4 ++-- 6 files changed, 11 insertions(+), 9 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/connected.c b/zebra/connected.c index 87cf8c8f20..b69c5c6e71 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -251,10 +251,10 @@ void connected_up(struct interface *ifp, struct connected *ifc) metric = (ifc->metric < (uint32_t)METRIC_MAX) ? ifc->metric : ifp->metric; rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, zvrf->table_id, metric, 0, 0, 0); + 0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0); rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, zvrf->table_id, metric, 0, 0, 0); + 0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index f5aca2341d..13dd9c8dc1 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1144,7 +1144,8 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, - zebra_flags, &p, NULL, &nh, RT_TABLE_MAIN, 0, 0, 0, 0); + zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, + 0, 0, 0, 0); else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, &nh, RT_TABLE_MAIN, diff --git a/zebra/rib.h b/zebra/rib.h index e6d6d87447..6b8097dd13 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -363,8 +363,8 @@ extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re); extern int rib_add(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, uint32_t mtu, - uint8_t distance, route_tag_t tag); + uint32_t nhe_id, uint32_t table_id, uint32_t metric, + uint32_t mtu, uint8_t distance, route_tag_t tag); extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a030356f38..2744e6da9a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -618,7 +618,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, gate, afi, nh_vrf_id); } rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, - &src_p, &nh, table, metric, mtu, distance, tag); + &src_p, &nh, nhe_id, table, metric, mtu, + distance, tag); } else { /* This is a multipath route */ uint8_t nhop_num; diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 725bb63a0d..3ba5d6ee73 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -102,7 +102,7 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry) nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop; rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, - zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0); + zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0, 0); } void route_read(struct zebra_ns *zns) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1ea11640d7..196d7f1218 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2947,8 +2947,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, int rib_add(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, uint32_t mtu, uint8_t distance, - route_tag_t tag) + uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint32_t mtu, + uint8_t distance, route_tag_t tag) { struct route_entry *re; struct nexthop *nexthop; -- cgit v1.2.3 From bbb322f292cccb0cb60008acb8b50c89b37a8a4a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 10:58:05 -0400 Subject: zebra: Make route entry nexthop groups point to our hash entry Make our route entry struct's re->ng nexthop group pointer just point to the nhe->nhg nexthop hash entry nexthop group. This will allow updates to the nexthop itself to propogate to our routes immediately. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 1 + zebra/zebra_rib.c | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2744e6da9a..7b38dd8bed 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -642,6 +642,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->table = table; re->uptime = monotime(NULL); re->tag = tag; + re->nhe_id = nhe_id; re->ng = nexthop_group_new(); for (;;) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 196d7f1218..df1f3df091 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2415,9 +2415,6 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (nhe) zebra_nhg_decrement_ref(nhe); - // TODO: We need to hold on nh's until refcnt is 0 right? - nexthops_free(re->ng->nexthop); - nexthop_group_delete(&re->ng); nexthops_free(re->fib_ng.nexthop); XFREE(MTYPE_RE, re); @@ -2651,8 +2648,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { - nexthops_free(re->ng->nexthop); - nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return 0; } @@ -2662,10 +2657,33 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - nhe = zebra_nhg_find(re->ng, re->vrf_id, 0); + /* Using a kernel that supports nexthop ojects */ + if (re->nhe_id) { + nhe = zebra_nhg_lookup_id(re->nhe_id); + } else { + nhe = zebra_nhg_find(re->ng, re->vrf_id, 0); + re->nhe_id = nhe->id; + } + + if (nhe) { + nhe->refcnt++; + + /* Freeing the nexthop structs we were using + * for lookup since it will just point + * to the hash entry group now. + */ + nexthops_free(re->ng->nexthop); + nexthop_group_delete(&re->ng); + /* Point to hash entry group */ + re->ng = &nhe->nhg; + + } else { + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find or create a nexthop hash entry for id=%u in a route entry", + re->nhe_id); + } - re->nhe_id = nhe->id; - nhe->refcnt++; /* Set default distance by route type. */ if (re->distance == 0) @@ -2950,8 +2968,8 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint32_t mtu, uint8_t distance, route_tag_t tag) { - struct route_entry *re; - struct nexthop *nexthop; + struct route_entry *re = NULL; + struct nexthop *nexthop = NULL; /* Allocate new route_entry structure. */ re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); @@ -2965,6 +2983,8 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->vrf_id = vrf_id; re->uptime = monotime(NULL); re->tag = tag; + re->nhe_id = nhe_id; + re->ng = nexthop_group_new(); /* Add nexthop. */ -- cgit v1.2.3 From 2614bf87643e1f019fb337fab5fe45c3be5752be Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 13:46:05 -0700 Subject: zebra: Add ifp to zebra-side rib_add Add an interface pointer for an nexthop group hash entry when we are getting a rib_add for a new route. Also, add the interface index to the `show nexthop-group` command. Signed-off-by: Stephen Worley --- zebra/interface.c | 1 - zebra/interface.h | 3 --- zebra/rt_netlink.c | 13 +++++++------ zebra/zebra_nhg.c | 1 + zebra/zebra_nhg.h | 8 ++++++++ zebra/zebra_rib.c | 1 + zebra/zebra_vty.c | 3 +++ 7 files changed, 20 insertions(+), 10 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/interface.c b/zebra/interface.c index 6b77f3c871..3eb0e68537 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -947,7 +947,6 @@ struct nhe_connected *nhe_connected_add(struct interface *ifp, struct zebra_if *zif = (struct zebra_if *)ifp->info; if_nhec = nhe_connected_new(); - if_nhec->ifp = ifp; /* Attach the nhe */ if_nhec->nhe = nhe; diff --git a/zebra/interface.h b/zebra/interface.h index 270cc868c0..7dccaeaccb 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -266,9 +266,6 @@ struct irdp_interface; /* Nexthop hash entry connected structure */ struct nhe_connected { - /* Attached interface */ - struct interface *ifp; - /* Connected nexthop hash entry */ struct nhg_hash_entry *nhe; }; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 73260ee18b..b2712d52f1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2313,16 +2313,17 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) nhe = zebra_nhg_find(&nhg, nh.vrf_id, id); if (nhe) { nhe->is_kernel_nh = true; - if (ifp) { - /* Add the nhe to the interface's list - * of connected nhe's - */ - nhe_connected_add(ifp, nhe); - } } else { return -1; } } + if (ifp) { + /* Add the nhe to the interface's list + * of connected nhe's + */ + // TODO: Don't add dupes + nhe_connected_add(ifp, nhe); + } SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); } else if (h->nlmsg_type == RTM_DELNEXTHOP) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ece1e1ccd5..5704cf0e23 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -108,6 +108,7 @@ static void *zebra_nhg_alloc(void *arg) nhe->refcnt = 0; nhe->is_kernel_nh = false; nhe->dplane_ref = zebra_router_get_next_sequence(); + nhe->ifp = NULL; nhe->nhg.nexthop = NULL; nexthop_group_copy(&nhe->nhg, ©->nhg); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index a7a97f5529..8b3f6502a1 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -35,6 +35,14 @@ struct nhg_hash_entry { struct nexthop_group nhg; + /* If this is not a group, it + * will be a single nexthop + * and must have an interface + * associated with it. + * Otherwise, this will be null. + */ + struct interface *ifp; + uint32_t refcnt; uint32_t dplane_ref; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index df1f3df091..8decb2210d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2666,6 +2666,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, } if (nhe) { + // TODO: Add interface pointer nhe->refcnt++; /* Freeing the nexthop structs we were using diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index cf728a649d..067b7a12a8 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1120,6 +1120,9 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, vty_out(vty, "\tValid: %d, Installed %d\n", nhe->flags & NEXTHOP_GROUP_VALID, nhe->flags & NEXTHOP_GROUP_INSTALLED); + if (nhe->ifp) + vty_out(vty, "\tInterface Index: %d\n", + nhe->ifp->ifindex); for (ALL_NEXTHOPS(nhe->nhg, nhop)) { vty_out(vty, "\t"); nexthop_group_write_nexthop(vty, nhop); -- cgit v1.2.3 From 77b76fc900db6db8b6a5f2f5a795123a0be547d7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 19 Mar 2019 17:06:01 -0400 Subject: Revert "zebra: Remove afi field in nexthop hash entry" This reverts commit be73fe9393aac58c7f4bdb5c8a98c24c6cda6d5d. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 10 ++++++++-- zebra/zebra_nhg.h | 4 +++- zebra/zebra_rib.c | 2 +- zebra/zebra_vty.c | 14 ++++++++++---- 4 files changed, 22 insertions(+), 8 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2da007fb04..df93557ad8 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -106,6 +106,7 @@ static void *zebra_nhg_alloc(void *arg) pthread_mutex_unlock(&lock); nhe->vrf_id = copy->vrf_id; + nhe->afi = copy->afi; nhe->refcnt = 0; nhe->is_kernel_nh = false; nhe->dplane_ref = zebra_router_get_next_sequence(); @@ -163,7 +164,7 @@ uint32_t zebra_nhg_hash_key(const void *arg) int key = 0x5a351234; - key = jhash_1word(nhe->vrf_id, key); + key = jhash_2words(nhe->vrf_id, nhe->afi, key); key = jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); @@ -188,6 +189,9 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->vrf_id != nhe2->vrf_id) return false; + if (nhe1->afi != nhe2->afi) + return false; + /* * Again we are not interested in looking at any recursively * resolved nexthops. Top level only @@ -229,6 +233,7 @@ struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) * * @nhg: Nexthop group we lookup with * @vrf_id: VRF id + * @afi: Address Family type * @id: ID we lookup with, 0 means its from us and we need to give it * an ID, otherwise its from the kernel as we use the ID it gave * us. @@ -236,13 +241,14 @@ struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) * Return: Hash entry found or created */ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, - vrf_id_t vrf_id, uint32_t id) + vrf_id_t vrf_id, afi_t afi, uint32_t id) { struct nhg_hash_entry lookup = {0}; struct nhg_hash_entry *nhe = NULL; lookup.id = id; lookup.vrf_id = vrf_id; + lookup.afi = afi; lookup.nhg = *nhg; diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 8b3f6502a1..761ed70d1a 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -30,6 +30,7 @@ struct nhg_hash_entry { uint32_t id; + afi_t afi; vrf_id_t vrf_id; bool is_kernel_nh; @@ -80,7 +81,8 @@ extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); extern struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, - vrf_id_t vrf_id, uint32_t id); + vrf_id_t vrf_id, afi_t afi, + uint32_t id); extern struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg); void zebra_nhg_free(void *arg); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8decb2210d..ff7a3a98da 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2661,7 +2661,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (re->nhe_id) { nhe = zebra_nhg_lookup_id(re->nhe_id); } else { - nhe = zebra_nhg_find(re->ng, re->vrf_id, 0); + nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, 0); re->nhe_id = nhe->id; } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 067b7a12a8..7022b9d57d 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1103,7 +1103,7 @@ DEFUN (ip_nht_default_route, } static void show_nexthop_group_cmd_helper(struct vty *vty, - struct zebra_vrf *zvrf) + struct zebra_vrf *zvrf, afi_t afi) { struct list *list = hash_to_list(zrouter.nhgs); struct nhg_hash_entry *nhe; @@ -1112,6 +1112,9 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) { struct nexthop *nhop; + if (nhe->afi != afi) + continue; + if (nhe->vrf_id != zvrf->vrf->vrf_id) continue; @@ -1134,11 +1137,14 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, DEFPY (show_nexthop_group, show_nexthop_group_cmd, - "show nexthop-group [vrf ]", + "show nexthop-group [vrf ]", SHOW_STR + IP_STR + IP6_STR "Show Nexthop Groups\n" VRF_FULL_CMD_HELP_STR) { + afi_t afi = v4 ? AFI_IP : AFI_IP6; struct zebra_vrf *zvrf; if (vrf_all) { @@ -1152,7 +1158,7 @@ DEFPY (show_nexthop_group, continue; vty_out(vty, "VRF: %s\n", vrf->name); - show_nexthop_group_cmd_helper(vty, zvrf); + show_nexthop_group_cmd_helper(vty, zvrf, afi); } return CMD_SUCCESS; @@ -1168,7 +1174,7 @@ DEFPY (show_nexthop_group, return CMD_SUCCESS; } - show_nexthop_group_cmd_helper(vty, zvrf); + show_nexthop_group_cmd_helper(vty, zvrf, afi); return CMD_SUCCESS; } -- cgit v1.2.3 From 85f5e76175f190ef13b7d883a256612380574ca6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 21 Mar 2019 10:47:19 -0400 Subject: zebra: Read in nexthop dependencies from the kernel Add functionality to read in a group from the kernel, create a hash entry for it, and add its nexthops to its dependency list. Further, we create its nhg struct separtely from this, copying over any nexthops it should reference directly into it. Thus, we have two types for representation of the nexthop group: nhe->nhg_depends->[nhe, nhe, nhe] nhe->nhg->nexthop->nexthop->nexthop Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 108 ++++++++++++++++++++++++++++++++++++----------------- zebra/zebra_nhg.c | 34 +++++++++++++---- zebra/zebra_nhg.h | 9 ++--- zebra/zebra_rib.c | 2 +- 4 files changed, 106 insertions(+), 47 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7a30178ecb..581dae710d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2170,40 +2170,59 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, /** * netlink_nexthop_process_group() - Iterate over nhmsg nexthop group * - * @tb: Netlink RTA data + * @tb: Netlink RTA data + * @nhg_depends: List of nexthops in the group (depends) + * @nhg: Nexthop group struct * - * Return: TODO: Not sure yet + * Return: Count of nexthops in the group */ -static int netlink_nexthop_process_group(struct rtattr **tb) +static int netlink_nexthop_process_group(struct rtattr **tb, + struct nexthop_group *nhg, + struct list **nhg_depends) { - int count; + int count = 0; struct nexthop_grp *n_grp = NULL; + struct nhg_hash_entry *depend = NULL; - n_grp = RTA_DATA(tb[NHA_GROUP]); + n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]); count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp)); if (!count || (count * sizeof(*n_grp)) != RTA_PAYLOAD(tb[NHA_GROUP])) { flog_warn(EC_ZEBRA_BAD_NHG_MESSAGE, "Invalid nexthop group received from the kernel"); - return -1; + return count; } // TODO: Need type for something? - // zlog_debug("group type: %d", - // *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); + zlog_debug("Nexthop group type: %d", + *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); + *nhg_depends = nhg_depend_new_list(); for (int i = 0; i < count; i++) { - // TODO: Lookup by id and if we already have entries - // for that id, delete it? - /* We do not care about nexthop_grp.weight at * this time. But we should figure out * how to adapt this to our code in * the future. */ - } + depend = zebra_nhg_lookup_id(n_grp[i].id); + if (depend) { + nhg_depend_add(*nhg_depends, depend); + /* + * If this is a nexthop with its own group + * dependencies, add them as well. Not sure its + * even possible to have a group within a group + * in the kernel. + */ + copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL); + } else { + flog_err( + EC_ZEBRA_NHG_SYNC, + "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table", + n_grp[i].id); + } + } return count; } @@ -2229,6 +2248,10 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct nexthop_group nhg = {0}; /* zebra's version of nexthops */ struct nexthop nh = {0}; + /* If its a group, array of nexthops */ + struct list *nhg_depends = NULL; + /* Count of nexthops in group array */ + int dep_count = 0; /* struct that goes into our tables */ struct nhg_hash_entry *nhe = NULL; struct rtattr *tb[NHA_MAX + 1]; @@ -2278,36 +2301,54 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) * If this is a group message its only going to have * an array of nexthop IDs associated with it */ - return -1; - netlink_nexthop_process_group(tb); - } else if (tb[NHA_BLACKHOLE]) { - /** - * This nexthop is just for blackhole-ing traffic, - * it should not have an OIF, GATEWAY, or ENCAP - */ - nh.type = NEXTHOP_TYPE_BLACKHOLE; - // TODO: Handle blackhole case - nh.bh_type = BLACKHOLE_UNSPEC; - } else if (tb[NHA_OIF]) { - /** - * This is a true new nexthop, so we need - * to parse the gateway and device info - */ - nh = netlink_nexthop_process_nh(tb, family, &ifp, - ns_id); + dep_count = netlink_nexthop_process_group(tb, &nhg, + &nhg_depends); + } else { + if (tb[NHA_BLACKHOLE]) { + /** + * This nexthop is just for blackhole-ing + * traffic, it should not have an OIF, GATEWAY, + * or ENCAP + */ + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = BLACKHOLE_UNSPEC; + } else if (tb[NHA_OIF]) { + /** + * This is a true new nexthop, so we need + * to parse the gateway and device info + */ + nh = netlink_nexthop_process_nh(tb, family, + &ifp, ns_id); + } + SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE); + if (nhm->nh_flags & RTNH_F_ONLINK) + SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); + + nexthop_group_add_sorted(&nhg, &nh); } if (!nhg.nexthop) return -1; if (nhe) { - /* This is a change to a group we already have */ + /* This is a change to a group we already have + */ nexthops_free(nhe->nhg.nexthop); - nhe->nhg.nexthop = NULL; - nexthop_group_copy(&nhe->nhg, &nhg); + if (dep_count) { + list_delete(&nhe->nhg_depends); + nhe->nhg_depends = nhg_depends; + /* Group is already allocated with depends */ + // TODO: Maybe better to just allocate both + // rather than doing each differently? + nhe->nhg = nhg; + } else { + nhe->nhg.nexthop = NULL; + nexthop_group_copy(&nhe->nhg, &nhg); + } } else { /* This is a new nexthop group */ - nhe = zebra_nhg_find(&nhg, nh.vrf_id, afi, id); + nhe = zebra_nhg_find(&nhg, nh.vrf_id, afi, id, + nhg_depends, dep_count); if (nhe) { nhe->is_kernel_nh = true; } else { @@ -2321,7 +2362,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) // TODO: Don't add dupes nhe_connected_add(ifp, nhe); } - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index df66fac8a6..82bbef3911 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -287,12 +287,6 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) -{ - // TODO: How this will work is yet to be determined - return NULL; -} - /** * zebra_nhg_find() - Find the zebra nhg in our table, or create it * @@ -302,11 +296,31 @@ struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) * @id: ID we lookup with, 0 means its from us and we need to give it * an ID, otherwise its from the kernel as we use the ID it gave * us. + * @dep_info: Array of nexthop dependency info (ID/weight) + * @dep_count: Count for the number of nexthop dependencies * * Return: Hash entry found or created + * + * The nhg and n_grp are fundementally the same thing (a group of nexthops). + * We are just using the nhg representation with routes and the n_grp + * is what the kernel gives us (a list of IDs). Our nhg_hash_entry + * will contain both. + * + * nhg_hash_entry example: + * + * nhe: + * ->nhg: + * .nexthop->nexthop->nexthop + * ->nhg_depends: + * .nhe->nhe->nhe + * + * Routes will use the nhg directly, and any updating of nexthops + * we have to do or flag setting, we use the nhg_depends. + * */ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, - vrf_id_t vrf_id, afi_t afi, uint32_t id) + vrf_id_t vrf_id, afi_t afi, uint32_t id, + struct list *nhg_depends, int dep_count) { struct nhg_hash_entry lookup = {0}; struct nhg_hash_entry *nhe = NULL; @@ -315,7 +329,10 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, lookup.vrf_id = vrf_id; lookup.afi = afi; lookup.nhg = *nhg; + lookup.nhg_depends = NULL; + if (dep_count) + lookup.nhg_depends = nhg_depends; nhe = hash_lookup(zrouter.nhgs, &lookup); @@ -333,6 +350,9 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, EC_ZEBRA_DUPLICATE_NHG_MESSAGE, "Nexthop Group from with ID (%d) is a duplicate, ignoring", id); + if (lookup.nhg_depends) + list_delete(&lookup.nhg_depends); + return NULL; } } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index f8cd3bb049..e741cc0cfc 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -100,11 +100,10 @@ extern uint32_t zebra_nhg_id_key(const void *arg); extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); -extern struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, - vrf_id_t vrf_id, afi_t afi, - uint32_t id); -extern struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, - struct nexthop_group *nhg); +extern struct nhg_hash_entry * +zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi, + uint32_t id, struct list *nhg_depends, int dep_count); + void zebra_nhg_free(void *arg); void zebra_nhg_release(struct nhg_hash_entry *nhe); void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ff7a3a98da..d71239abe9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2661,7 +2661,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (re->nhe_id) { nhe = zebra_nhg_lookup_id(re->nhe_id); } else { - nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, 0); + nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, 0, NULL, 0); re->nhe_id = nhe->id; } -- cgit v1.2.3 From 8e401b251f25be5d9daceab12c73b760a771df6e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 22 Mar 2019 13:11:07 -0400 Subject: zebra: Refactor nexthop group creation code to use allocated memory Simplify the code for nexthop hash entry creation. I made nexthop hash entry creation expect the nexthop group and depends to always be allocated before lookup. Before, it was only allocated if it had dependencies. I think it makes the code a bit more readable to go ahead an allocate even for single nexthops as well. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 138 ++++++++++++++++++++++++++++++++------------------- zebra/zebra_dplane.c | 26 ++++++---- zebra/zebra_nhg.c | 41 ++++++--------- zebra/zebra_nhg.h | 2 +- zebra/zebra_rib.c | 21 ++------ zebra/zebra_vty.c | 2 +- 6 files changed, 126 insertions(+), 104 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 581dae710d..6753a22ecc 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1895,9 +1895,6 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) // TODO: Scope? if (!nhe->id) { - // TODO: When we start using this with the ctx's we might not - // need to do ID assignment ourselves and just let the kernel - // handle it. flog_err( EC_ZEBRA_NHG_FIB_UPDATE, "Failed trying to update a nexthop group in the kernel that does not have an ID"); @@ -1907,9 +1904,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) addattr32(&req.n, sizeof(req), NHA_ID, nhe->id); if (cmd == RTM_NEWNEXTHOP) { - // TODO: IF not a group - const struct nexthop_group nhg = nhe->nhg; - const struct nexthop *nh = nhg.nexthop; + const struct nexthop *nh = nhe->nhg->nexthop; if (nhe->afi == AFI_IP) req.nhm.nh_family = AF_INET; @@ -1917,8 +1912,6 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) req.nhm.nh_family = AF_INET6; switch (nh->type) { - // TODO: Need AF for just index also - // just use dest? case NEXTHOP_TYPE_IPV4_IFINDEX: addattr_l(&req.n, sizeof(req), NHA_GATEWAY, &nh->gate.ipv4, IPV4_MAX_BYTELEN); @@ -2100,26 +2093,28 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * * Return: New nexthop */ -static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, - unsigned char family, - struct interface **ifp, - ns_id_t ns_id) +static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb, + unsigned char family, + struct interface **ifp, + ns_id_t ns_id) { - struct nexthop nh = {0}; + struct nexthop *nh = NULL; void *gate = NULL; + enum nexthop_types_t type = 0; int if_index; size_t sz; if_index = *(int *)RTA_DATA(tb[NHA_OIF]); + if (tb[NHA_GATEWAY]) { switch (family) { case AF_INET: - nh.type = NEXTHOP_TYPE_IPV4_IFINDEX; + type = NEXTHOP_TYPE_IPV4_IFINDEX; sz = 4; break; case AF_INET6: - nh.type = NEXTHOP_TYPE_IPV6_IFINDEX; + type = NEXTHOP_TYPE_IPV6_IFINDEX; sz = 16; break; default: @@ -2127,26 +2122,35 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, EC_ZEBRA_BAD_NHG_MESSAGE, "Nexthop gateway with bad address family (%d) received from kernel", family); - return nh; + return NULL; } gate = RTA_DATA(tb[NHA_GATEWAY]); - memcpy(&(nh.gate), gate, sz); } else { - nh.type = NEXTHOP_TYPE_IFINDEX; + type = NEXTHOP_TYPE_IFINDEX; } - nh.ifindex = if_index; + /* Allocate the new nexthop */ + nh = nexthop_new(); - *ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex); + if (type) + nh->type = type; + + if (gate) + memcpy(&(nh->gate), gate, sz); + + if (if_index) + nh->ifindex = if_index; + + *ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh->ifindex); if (ifp) { - nh.vrf_id = (*ifp)->vrf_id; + nh->vrf_id = (*ifp)->vrf_id; } else { flog_warn( EC_ZEBRA_UNKNOWN_INTERFACE, "%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT", - __PRETTY_FUNCTION__, nh.ifindex); + __PRETTY_FUNCTION__, nh->ifindex); - nh.vrf_id = VRF_DEFAULT; + nh->vrf_id = VRF_DEFAULT; } if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) { @@ -2159,7 +2163,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, } if (num_labels) { - nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, + nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); } } @@ -2215,7 +2219,8 @@ static int netlink_nexthop_process_group(struct rtattr **tb, * in the kernel. */ - copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL); + copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, + NULL); } else { flog_err( EC_ZEBRA_NHG_SYNC, @@ -2245,9 +2250,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct interface *ifp = NULL; struct nhmsg *nhm = NULL; /* struct for nexthop group abstraction */ - struct nexthop_group nhg = {0}; - /* zebra's version of nexthops */ - struct nexthop nh = {0}; + struct nexthop_group *nhg = NULL; + struct nexthop *nh = NULL; /* If its a group, array of nexthops */ struct list *nhg_depends = NULL; /* Count of nexthops in group array */ @@ -2296,12 +2300,14 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) nhe = zebra_nhg_lookup_id(id); if (h->nlmsg_type == RTM_NEWNEXTHOP) { + nhg = nexthop_group_new(); + if (tb[NHA_GROUP]) { /** * If this is a group message its only going to have * an array of nexthop IDs associated with it */ - dep_count = netlink_nexthop_process_group(tb, &nhg, + dep_count = netlink_nexthop_process_group(tb, nhg, &nhg_depends); } else { if (tb[NHA_BLACKHOLE]) { @@ -2310,8 +2316,9 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) * traffic, it should not have an OIF, GATEWAY, * or ENCAP */ - nh.type = NEXTHOP_TYPE_BLACKHOLE; - nh.bh_type = BLACKHOLE_UNSPEC; + nh = nexthop_new(); + nh->type = NEXTHOP_TYPE_BLACKHOLE; + nh->bh_type = BLACKHOLE_UNSPEC; } else if (tb[NHA_OIF]) { /** * This is a true new nexthop, so we need @@ -2320,40 +2327,69 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) nh = netlink_nexthop_process_nh(tb, family, &ifp, ns_id); } - SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE); - if (nhm->nh_flags & RTNH_F_ONLINK) - SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); + if (nh) { + SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE); + if (nhm->nh_flags & RTNH_F_ONLINK) + SET_FLAG(nh->flags, + NEXTHOP_FLAG_ONLINK); - nexthop_group_add_sorted(&nhg, &nh); + nexthop_group_add_sorted(nhg, nh); + } else { + flog_warn( + EC_ZEBRA_BAD_NHG_MESSAGE, + "Invalid Nexthop message received from the kernel with ID (%u)", + id); + return -1; + } } - if (!nhg.nexthop) + if (!nhg->nexthop) { + /* Nothing to lookup */ + zebra_nhg_free_group_depends(nhg, nhg_depends); return -1; + } if (nhe) { /* This is a change to a group we already have */ - nexthops_free(nhe->nhg.nexthop); - if (dep_count) { - list_delete(&nhe->nhg_depends); + + /* Free what's already there */ + zebra_nhg_free_members(nhe); + + /* Update with new info */ + nhe->nhg = nhg; + if (dep_count) nhe->nhg_depends = nhg_depends; - /* Group is already allocated with depends */ - // TODO: Maybe better to just allocate both - // rather than doing each differently? - nhe->nhg = nhg; - } else { - nhe->nhg.nexthop = NULL; - nexthop_group_copy(&nhe->nhg, &nhg); - } + } else { /* This is a new nexthop group */ - nhe = zebra_nhg_find(&nhg, nh.vrf_id, afi, id, + nhe = zebra_nhg_find(nhg, nhg->nexthop->vrf_id, afi, id, nhg_depends, dep_count); - if (nhe) { - nhe->is_kernel_nh = true; - } else { + if (!nhe) { + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find or create a nexthop hash entry for ID (%u) from the kernel", + id); + zebra_nhg_free_group_depends(nhg, nhg_depends); return -1; } + + nhe->is_kernel_nh = true; + if (id != nhe->id) { + /* Duplicate but with different ID from + * the kernel */ + + /* The kernel allows duplicate nexthops + * as long as they have different IDs. + * We are ignoring those to prevent + * syncing problems with the kernel + * changes. + */ + flog_warn( + EC_ZEBRA_DUPLICATE_NHG_MESSAGE, + "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring", + id); + } } if (ifp) { /* Add the nhe to the interface's list diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index f20242bfc2..0e806ff7f7 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -96,7 +96,6 @@ struct dplane_route_info { uint32_t zd_nexthop_mtu; /* Nexthop hash entry */ - // TODO: Adjust the others as needed struct nhg_hash_entry zd_nhe; /* Nexthops */ @@ -471,7 +470,7 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: { - nexthops_free((*pctx)->u.rinfo.zd_nhe.nhg.nexthop); + zebra_nhg_free_members(&(*pctx)->u.rinfo.zd_nhe); break; } @@ -1495,8 +1494,7 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct nhg_hash_entry *nhe) { - struct zebra_ns *zns; - struct zebra_vrf *zvrf; + struct zebra_ns *zns = NULL; int ret = EINVAL; @@ -1507,13 +1505,23 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; /* Copy over nhe info */ - ctx->u.rinfo.zd_nhe = *nhe; - ctx->u.rinfo.zd_nhe.nhg.nexthop = NULL; - nexthop_group_copy(&(ctx->u.rinfo.zd_nhe.nhg), &nhe->nhg); + ctx->u.rinfo.zd_nhe.id = nhe->id; + ctx->u.rinfo.zd_nhe.vrf_id = nhe->vrf_id; + ctx->u.rinfo.zd_nhe.afi = nhe->afi; + ctx->u.rinfo.zd_nhe.refcnt = nhe->refcnt; + ctx->u.rinfo.zd_nhe.is_kernel_nh = nhe->is_kernel_nh; + ctx->u.rinfo.zd_nhe.dplane_ref = nhe->dplane_ref; + ctx->u.rinfo.zd_nhe.ifp = nhe->ifp; + + ctx->u.rinfo.zd_nhe.nhg = nexthop_group_new(); + nexthop_group_copy(ctx->u.rinfo.zd_nhe.nhg, nhe->nhg); + + if (nhe->nhg_depends) + ctx->u.rinfo.zd_nhe.nhg_depends = list_dup(nhe->nhg_depends); + /* Extract ns info - can't use pointers to 'core' structs */ - zvrf = vrf_info_lookup(nhe->vrf_id); - zns = zvrf->zns; + zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; // TODO: Might not need to mark this as an update, since // it probably won't require two messages diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 789e371da5..522bf6a9a2 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -161,17 +161,11 @@ static void *zebra_nhg_alloc(void *arg) pthread_mutex_unlock(&lock); nhe->nhg_depends = NULL; - nhe->nhg.nexthop = NULL; - if (copy->nhg_depends) { + if (copy->nhg_depends) nhe->nhg_depends = copy->nhg_depends; - /* These have already been allocated when - * building the dependency list - */ - nhe->nhg = copy->nhg; - } else { - nexthop_group_copy(&nhe->nhg, ©->nhg); - } + + nhe->nhg = copy->nhg; nhe->vrf_id = copy->vrf_id; nhe->afi = copy->afi; @@ -232,7 +226,7 @@ uint32_t zebra_nhg_hash_key(const void *arg) key = jhash_2words(nhe->vrf_id, nhe->afi, key); - key = jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); + key = jhash_1word(zebra_nhg_hash_key_nexthop_group(nhe->nhg), key); return key; } @@ -261,9 +255,9 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) * Again we are not interested in looking at any recursively * resolved nexthops. Top level only */ - for (nh1 = nhe1->nhg.nexthop; nh1; nh1 = nh1->next) { + for (nh1 = nhe1->nhg->nexthop; nh1; nh1 = nh1->next) { uint32_t inner_nh_count = 0; - for (nh2 = nhe2->nhg.nexthop; nh2; nh2 = nh2->next) { + for (nh2 = nhe2->nhg->nexthop; nh2; nh2 = nh2->next) { if (inner_nh_count == nh_count) { break; } @@ -290,16 +284,16 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) /** * zebra_nhg_find() - Find the zebra nhg in our table, or create it * - * @nhg: Nexthop group we lookup with - * @vrf_id: VRF id - * @afi: Address Family type - * @id: ID we lookup with, 0 means its from us and we need to give it - * an ID, otherwise its from the kernel as we use the ID it gave - * us. - * @dep_info: Array of nexthop dependency info (ID/weight) - * @dep_count: Count for the number of nexthop dependencies + * @nhg: Nexthop group we lookup with + * @vrf_id: VRF id + * @afi: Address Family type + * @id: ID we lookup with, 0 means its from us and we + * need to give it an ID, otherwise its from the + * kernel as we use the ID it gave us. + * @nhg_depends: Nexthop dependencies + * @dep_count: Count for the number of nexthop dependencies * - * Return: Hash entry found or created + * Return: Hash entry found or created * * The nhg and n_grp are fundementally the same thing (a group of nexthops). * We are just using the nhg representation with routes and the n_grp @@ -387,10 +381,7 @@ void zebra_nhg_free(void *arg) nhe = (struct nhg_hash_entry *)arg; - if (nhe->nhg_depends) - list_delete(&nhe->nhg_depends); - - nexthops_free(nhe->nhg.nexthop); + zebra_nhg_free_members(nhe); XFREE(MTYPE_NHG, nhe); } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 287aaf275f..634a416e1b 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -34,7 +34,7 @@ struct nhg_hash_entry { vrf_id_t vrf_id; bool is_kernel_nh; - struct nexthop_group nhg; + struct nexthop_group *nhg; /* If this is not a group, it * will be a single nexthop diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d71239abe9..e882c9d694 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2648,6 +2648,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { + zebra_nhg_free_group_depends(re->ng, NULL); XFREE(MTYPE_RE, re); return 0; } @@ -2657,27 +2658,13 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - /* Using a kernel that supports nexthop ojects */ - if (re->nhe_id) { - nhe = zebra_nhg_lookup_id(re->nhe_id); - } else { - nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, 0, NULL, 0); - re->nhe_id = nhe->id; - } + nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, re->nhe_id, NULL, 0); if (nhe) { // TODO: Add interface pointer + re->ng = nhe->nhg; + re->nhe_id = nhe->id; nhe->refcnt++; - - /* Freeing the nexthop structs we were using - * for lookup since it will just point - * to the hash entry group now. - */ - nexthops_free(re->ng->nexthop); - nexthop_group_delete(&re->ng); - /* Point to hash entry group */ - re->ng = &nhe->nhg; - } else { flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7cf82118df..c2a9d091d2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1138,7 +1138,7 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, vty_out(vty, "\n"); } - for (ALL_NEXTHOPS(nhe->nhg, nhop)) { + for (ALL_NEXTHOPS_PTR(nhe->nhg, nhop)) { vty_out(vty, "\t"); nexthop_group_write_nexthop(vty, nhop); } -- cgit v1.2.3 From 2d6cd1f007c860ad4c76e7efbbb0bf5b4226af0c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 19:40:23 -0400 Subject: zebra: Always copy nhg and depends on nhe alloc Changed our alloc function to just copy the nhg and nhg_depends. This makes the zebra_nhg_find code a little bit cleaner, hopefully preventing bugs. The only issue with this is that it makes us have to loop over the nexthops in a group an extra time for the copies. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 3 ++- zebra/zebra_nhg.c | 10 ++++------ zebra/zebra_rib.c | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 42daefeea9..ea81d180db 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2399,12 +2399,13 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* This is a new nexthop group */ nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends, dep_count); + zebra_nhg_free_group_depends(nhg, nhg_depends); + if (!nhe) { flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, "Zebra failed to find or create a nexthop hash entry for ID (%u) from the kernel", id); - zebra_nhg_free_group_depends(nhg, nhg_depends); return -1; } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 140e6a9abf..3c78ce5253 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -185,9 +185,10 @@ static void *zebra_nhg_alloc(void *arg) nhe->nhg_depends = NULL; if (copy->nhg_depends) - nhe->nhg_depends = copy->nhg_depends; + nhe->nhg_depends = nhg_depend_dup_list(copy->nhg_depends); - nhe->nhg = copy->nhg; + nhe->nhg = nexthop_group_new(); + nexthop_group_copy(nhe->nhg, copy->nhg); nhe->vrf_id = copy->vrf_id; nhe->afi = copy->afi; @@ -352,11 +353,8 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, else nhe = hash_lookup(zrouter.nhgs, &lookup); - if (!nhe) { + if (!nhe) nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); - } else { - zebra_nhg_free_group_depends(nhg, nhg_depends); - } return nhe; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index e882c9d694..a5b939baa9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2662,6 +2662,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (nhe) { // TODO: Add interface pointer + zebra_nhg_free_group_depends(re->ng, NULL); re->ng = nhe->nhg; re->nhe_id = nhe->id; nhe->refcnt++; -- cgit v1.2.3 From 20822f9d2e450cebfefbb14cc70a189a52df063c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 10:56:52 -0400 Subject: zebra: Add equivalence function for nhg_depends Add a helper function to allow us to check if two nhg_hash_entry's dependency lists are equal. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 232 ++++++++++++++++++++++++++++------------------------- zebra/zebra_nhg.c | 61 +++++++++----- zebra/zebra_rib.c | 25 +++++- 3 files changed, 187 insertions(+), 131 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3e377eb770..7917e3046e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -324,13 +324,14 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels) static struct nexthop parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, enum blackhole_type bh_type, int index, void *prefsrc, - void *gate, afi_t afi, vrf_id_t nh_vrf_id) + void *gate, afi_t afi, vrf_id_t vrf_id) { struct interface *ifp = NULL; struct nexthop nh = {0}; mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; + vrf_id_t nh_vrf_id = vrf_id; size_t sz = (afi == AFI_IP) ? 4 : 16; if (bh_type == BLACKHOLE_UNSPEC) { @@ -378,6 +379,114 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, return nh; } +static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, + struct route_entry *re, + struct rtmsg *rtm, + struct rtnexthop *rtnh, + struct rtattr **tb, + void *prefsrc, vrf_id_t vrf_id) +{ + void *gate = NULL; + struct interface *ifp = NULL; + int index = 0; + /* MPLS labels */ + mpls_label_t labels[MPLS_MAX_LABELS] = {0}; + int num_labels = 0; + struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; + + int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); + vrf_id_t nh_vrf_id = vrf_id; + + re->ng = nexthop_group_new(); + + for (;;) { + struct nexthop *nh = NULL; + + if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len) + break; + + index = rtnh->rtnh_ifindex; + if (index) { + /* + * Yes we are looking this up + * for every nexthop and just + * using the last one looked + * up right now + */ + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), + index); + if (ifp) + nh_vrf_id = ifp->vrf_id; + else { + flog_warn( + EC_ZEBRA_UNKNOWN_INTERFACE, + "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT", + __PRETTY_FUNCTION__, index); + nh_vrf_id = VRF_DEFAULT; + } + } else + nh_vrf_id = vrf_id; + + if (rtnh->rtnh_len > sizeof(*rtnh)) { + memset(rtnh_tb, 0, sizeof(rtnh_tb)); + + netlink_parse_rtattr(rtnh_tb, RTA_MAX, RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh)); + if (rtnh_tb[RTA_GATEWAY]) + gate = RTA_DATA(rtnh_tb[RTA_GATEWAY]); + if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE] + && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE]) + == LWTUNNEL_ENCAP_MPLS) { + num_labels = parse_encap_mpls( + rtnh_tb[RTA_ENCAP], labels); + } + } + + if (gate) { + if (rtm->rtm_family == AF_INET) { + if (index) + nh = route_entry_nexthop_ipv4_ifindex_add( + re, gate, prefsrc, index, + nh_vrf_id); + else + nh = route_entry_nexthop_ipv4_add( + re, gate, prefsrc, nh_vrf_id); + } else if (rtm->rtm_family == AF_INET6) { + if (index) + nh = route_entry_nexthop_ipv6_ifindex_add( + re, gate, index, nh_vrf_id); + else + nh = route_entry_nexthop_ipv6_add( + re, gate, nh_vrf_id); + } + } else + nh = route_entry_nexthop_ifindex_add(re, index, + nh_vrf_id); + + if (nh) { + if (num_labels) + nexthop_add_labels(nh, ZEBRA_LSP_STATIC, + num_labels, labels); + + if (rtnh->rtnh_flags & RTNH_F_ONLINK) + SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); + } + + if (rtnh->rtnh_len == 0) + break; + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + uint8_t nhop_num = nexthop_group_nexthop_num(re->ng); + + if (!nhop_num) + nexthop_group_delete(&re->ng); + + return nhop_num; +} + /* Looking up routing table by netlink interface. */ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, int startup) @@ -606,8 +715,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, afi = AFI_IP6; if (h->nlmsg_type == RTM_NEWROUTE) { - struct interface *ifp; - vrf_id_t nh_vrf_id = vrf_id; if (!tb[RTA_MULTIPATH]) { struct nexthop nh = {0}; @@ -615,22 +722,16 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (!nhe_id) { nh = parse_nexthop_unicast( ns_id, rtm, tb, bh_type, index, prefsrc, - gate, afi, nh_vrf_id); + gate, afi, vrf_id); } rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, &nh, nhe_id, table, metric, mtu, distance, tag); } else { /* This is a multipath route */ - uint8_t nhop_num; struct route_entry *re; struct rtnexthop *rtnh = (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); - /* MPLS labels */ - mpls_label_t labels[MPLS_MAX_LABELS] = {0}; - int num_labels = 0; - - len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); re->type = proto; @@ -643,108 +744,23 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->uptime = monotime(NULL); re->tag = tag; re->nhe_id = nhe_id; - re->ng = nexthop_group_new(); - - for (;;) { - struct nexthop *nh = NULL; - - if (len < (int)sizeof(*rtnh) - || rtnh->rtnh_len > len) - break; - - index = rtnh->rtnh_ifindex; - if (index) { - /* - * Yes we are looking this up - * for every nexthop and just - * using the last one looked - * up right now - */ - ifp = if_lookup_by_index_per_ns( - zebra_ns_lookup(ns_id), - index); - if (ifp) - nh_vrf_id = ifp->vrf_id; - else { - flog_warn( - EC_ZEBRA_UNKNOWN_INTERFACE, - "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT", - __PRETTY_FUNCTION__, - index); - nh_vrf_id = VRF_DEFAULT; - } - } else - nh_vrf_id = vrf_id; - - gate = 0; - if (rtnh->rtnh_len > sizeof(*rtnh)) { - memset(tb, 0, sizeof(tb)); - netlink_parse_rtattr( - tb, RTA_MAX, RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof(*rtnh)); - if (tb[RTA_GATEWAY]) - gate = RTA_DATA( - tb[RTA_GATEWAY]); - if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE] - && *(uint16_t *)RTA_DATA( - tb[RTA_ENCAP_TYPE]) - == LWTUNNEL_ENCAP_MPLS) { - num_labels = parse_encap_mpls( - tb[RTA_ENCAP], labels); - } - } - - if (gate) { - if (rtm->rtm_family == AF_INET) { - if (index) - nh = route_entry_nexthop_ipv4_ifindex_add( - re, gate, - prefsrc, index, - nh_vrf_id); - else - nh = route_entry_nexthop_ipv4_add( - re, gate, - prefsrc, - nh_vrf_id); - } else if (rtm->rtm_family - == AF_INET6) { - if (index) - nh = route_entry_nexthop_ipv6_ifindex_add( - re, gate, index, - nh_vrf_id); - else - nh = route_entry_nexthop_ipv6_add( - re, gate, - nh_vrf_id); - } - } else - nh = route_entry_nexthop_ifindex_add( - re, index, nh_vrf_id); - - if (nh && num_labels) - nexthop_add_labels(nh, ZEBRA_LSP_STATIC, - num_labels, labels); - - if (nh && (rtnh->rtnh_flags & RTNH_F_ONLINK)) - SET_FLAG(nh->flags, - NEXTHOP_FLAG_ONLINK); - - if (rtnh->rtnh_len == 0) - break; - len -= NLMSG_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); + if (!nhe_id) { + uint8_t nhop_num = + parse_multipath_nexthops_unicast( + ns_id, re, rtm, rtnh, tb, + prefsrc, vrf_id); + + zserv_nexthop_num_warn( + __func__, (const struct prefix *)&p, + nhop_num); } - nhop_num = nexthop_group_nexthop_num(re->ng); - zserv_nexthop_num_warn( - __func__, (const struct prefix *)&p, nhop_num); - if (nhop_num == 0) { - nexthop_group_delete(&re->ng); - XFREE(MTYPE_RE, re); - } else + if (nhe_id || re->ng) rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, re); + else + XFREE(MTYPE_RE, re); } } else { if (!tb[RTA_MULTIPATH]) { @@ -2400,7 +2416,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else { /* This is a new nexthop group */ nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends, - dep_count); + true); zebra_nhg_free_group_depends(nhg, nhg_depends); if (!nhe) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 92198bad03..c698d1099a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -144,6 +144,41 @@ zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id) return match; } +/** + * zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal + * + * @nhe1: Nexthop group hash entry + * @nhe2: Nexthop group hash entry + * + * Return: True if equal + * + * We don't care about ordering of the dependencies. If they contain + * the same nhe ID's, they are equivalent. + */ +static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1, + const struct nhg_hash_entry *nhe2) +{ + struct listnode *ln = NULL; + struct nhg_depend *n_dp = NULL; + + if (!nhe1->nhg_depends && !nhe2->nhg_depends) + return true; + + if ((nhe1->nhg_depends && !nhe2->nhg_depends) + || (nhe2->nhg_depends && !nhe1->nhg_depends)) + return false; + + if (listcount(nhe1->nhg_depends) != listcount(nhe2->nhg_depends)) + return false; + + for (ALL_LIST_ELEMENTS_RO(nhe1->nhg_depends, ln, n_dp)) { + if (!zebra_nhg_depends_lookup_id(nhe2, n_dp->nhe->id)) + return false; + } + + return true; +} + /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table * @@ -212,6 +247,10 @@ static void *zebra_nhg_alloc(void *arg) zebra_nhg_insert_id(nhe); + /* Send it to the kernel */ + if (!nhe->is_kernel_nh) + zebra_nhg_install_kernel(nhe); + return nhe; } @@ -275,8 +314,6 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) { const struct nhg_hash_entry *nhe1 = arg1; const struct nhg_hash_entry *nhe2 = arg2; - struct nexthop *nh1, *nh2; - uint32_t nh_count = 0; if (nhe1->vrf_id != nhe2->vrf_id) return false; @@ -284,24 +321,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->afi != nhe2->afi) return false; - /* - * Again we are not interested in looking at any recursively - * resolved nexthops. Top level only - */ - for (nh1 = nhe1->nhg->nexthop; nh1; nh1 = nh1->next) { - uint32_t inner_nh_count = 0; - for (nh2 = nhe2->nhg->nexthop; nh2; nh2 = nh2->next) { - if (inner_nh_count == nh_count) { - break; - } - inner_nh_count++; - } - - if (!nexthop_same(nh1, nh2)) - return false; - - nh_count++; - } + if (!zebra_nhg_depends_equal(nhe1, nhe2)) + return false; return true; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a5b939baa9..558dbd33e0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2638,6 +2638,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_node *rn; struct route_entry *same = NULL; struct nhg_hash_entry *nhe = NULL; + struct list *nhg_depends = NULL; int ret = 0; if (!re) @@ -2648,7 +2649,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { - zebra_nhg_free_group_depends(re->ng, NULL); + zebra_nhg_free_group_depends(re->ng, nhg_depends); XFREE(MTYPE_RE, re); return 0; } @@ -2658,11 +2659,29 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, re->nhe_id, NULL, 0); + /* If its a group, create a dependency list */ + if (re->ng && re->ng->nexthop->next) { + struct nexthop *nh = NULL; + struct nexthop lookup = {0}; + struct nhg_hash_entry *depend = NULL; + + nhg_depends = nhg_depend_new_list(); + + for (ALL_NEXTHOPS_PTR(re->ng, nh)) { + lookup = *nh; + /* Clear it, since its a group */ + lookup.next = NULL; + depend = zebra_nhg_find_nexthop(&lookup, afi); + nhg_depend_add(nhg_depends, depend); + } + } + + nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, re->nhe_id, nhg_depends, + false); if (nhe) { // TODO: Add interface pointer - zebra_nhg_free_group_depends(re->ng, NULL); + zebra_nhg_free_group_depends(re->ng, nhg_depends); re->ng = nhe->nhg; re->nhe_id = nhe->id; nhe->refcnt++; -- cgit v1.2.3 From 86946a2207c3f2c177b478c9cf64f491a922df5c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 1 Apr 2019 12:21:52 -0400 Subject: zebra: Update rib_add_multipath with increment nhe Update rib_add_multipath to use the reference count increment function for nexthop group hash entries. Signed-off-by: Stephen Worley --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 558dbd33e0..d33b8494b0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2684,7 +2684,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, zebra_nhg_free_group_depends(re->ng, nhg_depends); re->ng = nhe->nhg; re->nhe_id = nhe->id; - nhe->refcnt++; + zebra_nhg_increment_ref(nhe); } else { flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, -- cgit v1.2.3 From ab942eb2853310fa76e1bcdad422eed441adeb00 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 1 Apr 2019 12:24:16 -0400 Subject: zebra: Protocol side nhg_hash_entry afi fix Default the afi of the nexthop to the route entry using it. If it turns out to be a group, update the afi to AFI_UNSPEC. Signed-off-by: Stephen Worley --- zebra/zebra_rib.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d33b8494b0..3155570df5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2639,6 +2639,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_entry *same = NULL; struct nhg_hash_entry *nhe = NULL; struct list *nhg_depends = NULL; + /* Default to route afi */ + afi_t nhg_afi = afi; int ret = 0; if (!re) @@ -2671,13 +2673,18 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, lookup = *nh; /* Clear it, since its a group */ lookup.next = NULL; + /* Use the route afi here, since a single nh */ depend = zebra_nhg_find_nexthop(&lookup, afi); nhg_depend_add(nhg_depends, depend); } + + /* change the afi for group */ + if (listcount(nhg_depends)) + nhg_afi = AFI_UNSPEC; } - nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, re->nhe_id, nhg_depends, - false); + nhe = zebra_nhg_find(re->ng, re->vrf_id, nhg_afi, re->nhe_id, + nhg_depends, false); if (nhe) { // TODO: Add interface pointer -- cgit v1.2.3 From 0c8215cbab59480616fe31d8a81323070a21137b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 13 May 2019 17:10:34 -0700 Subject: zebra,lib: Refactor depends to RB tree Refactor the depends to use an RB tree instead of a list. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 7 ++ lib/nexthop_group.h | 1 + zebra/rt_netlink.c | 70 ++++++------ zebra/zebra_dplane.c | 105 ++++++++++++++---- zebra/zebra_dplane.h | 11 +- zebra/zebra_nhg.c | 308 +++++++++++++++++++++++++++------------------------ zebra/zebra_nhg.h | 54 +++++++-- zebra/zebra_rib.c | 20 ++-- zebra/zebra_vty.c | 12 +- 9 files changed, 359 insertions(+), 229 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 9564321d38..527039ac63 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -122,6 +122,13 @@ void nexthop_group_delete(struct nexthop_group **nhg) XFREE(MTYPE_NEXTHOP_GROUP, *nhg); } +void nexthop_group_free_delete(struct nexthop_group **nhg) +{ + if ((*nhg)->nexthop) + nexthops_free((*nhg)->nexthop); + nexthop_group_delete(nhg); +} + /* Add nexthop to the end of a nexthop list. */ void _nexthop_add(struct nexthop **target, struct nexthop *nexthop) { diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 4f4d40eb33..5193c943c4 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -41,6 +41,7 @@ struct nexthop_group { struct nexthop_group *nexthop_group_new(void); void nexthop_group_delete(struct nexthop_group **nhg); +void nexthop_group_free_delete(struct nexthop_group **nhg); void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7917e3046e..f7e72e243f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1888,26 +1888,24 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) * * @n: Netlink message header struct * @req_size: Size allocated for this message - * @nhg_depends: List of entry dependencies + * @depends_info: Array of depend_info structs + * @count: How many depencies there are */ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, - struct list *nhg_depends) + const struct depend_info *depends_info, + const uint8_t count) { - int count = listcount(nhg_depends); - int i = 0; struct nexthop_grp grp[count]; - struct listnode *dp_node = NULL; - struct nhg_depend *n_dp = NULL; memset(grp, 0, sizeof(grp)); if (count) { - for (ALL_LIST_ELEMENTS_RO(nhg_depends, dp_node, n_dp)) { - grp[i++].id = n_dp->nhe->id; + for (int i = 0; i < count; i++) { + grp[i].id = depends_info[i].id; + grp[i].weight = depends_info[i].weight; } + addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp)); } - - addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp)); } /** @@ -1927,8 +1925,6 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) memset(&req, 0, sizeof(req)); - const struct nhg_hash_entry *nhe = dplane_ctx_get_nhe(ctx); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; @@ -1937,25 +1933,31 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) req.nhm.nh_family = AF_UNSPEC; // TODO: Scope? - if (!nhe->id) { + uint32_t id = dplane_ctx_get_nhe_id(ctx); + + if (!id) { flog_err( EC_ZEBRA_NHG_FIB_UPDATE, "Failed trying to update a nexthop group in the kernel that does not have an ID"); return -1; } - addattr32(&req.n, sizeof(req), NHA_ID, nhe->id); + addattr32(&req.n, sizeof(req), NHA_ID, id); if (cmd == RTM_NEWNEXTHOP) { - if (nhe->nhg_depends) { - _netlink_nexthop_build_group(&req.n, sizeof(req), - nhe->nhg_depends); - } else { - const struct nexthop *nh = nhe->nhg->nexthop; + if (dplane_ctx_get_nhe_depends_count(ctx)) + _netlink_nexthop_build_group( + &req.n, sizeof(req), + dplane_ctx_get_nhe_depends_info(ctx), + dplane_ctx_get_nhe_depends_count(ctx)); + else { + const struct nexthop *nh = + dplane_ctx_get_nhe_ng(ctx)->nexthop; + afi_t afi = dplane_ctx_get_nhe_afi(ctx); - if (nhe->afi == AFI_IP) + if (afi == AFI_IP) req.nhm.nh_family = AF_INET; - else if (nhe->afi == AFI_IP6) + else if (afi == AFI_IP6) req.nhm.nh_family = AF_INET6; switch (nh->type) { @@ -1998,7 +2000,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) return -1; } - _netlink_nexthop_debug(cmd, nhe->id); + _netlink_nexthop_debug(cmd, id); return netlink_talk_info(netlink_talk_filter, &req.n, dplane_ctx_get_ns(ctx), 0); @@ -2223,14 +2225,14 @@ static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb, * netlink_nexthop_process_group() - Iterate over nhmsg nexthop group * * @tb: Netlink RTA data - * @nhg_depends: List of nexthops in the group (depends) + * @nhg_depends: Tree head of nexthops in the group (depends) * @nhg: Nexthop group struct * * Return: Count of nexthops in the group */ static int netlink_nexthop_process_group(struct rtattr **tb, struct nexthop_group *nhg, - struct list **nhg_depends) + struct nhg_depends_head *nhg_depends) { int count = 0; struct nexthop_grp *n_grp = NULL; @@ -2249,7 +2251,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, zlog_debug("Nexthop group type: %d", *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); - *nhg_depends = nhg_depend_new_list(); + zebra_nhg_depends_head_init(nhg_depends); for (int i = 0; i < count; i++) { /* We do not care about nexthop_grp.weight at @@ -2259,7 +2261,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, */ depend = zebra_nhg_lookup_id(n_grp[i].id); if (depend) { - nhg_depend_add(*nhg_depends, depend); + zebra_nhg_depends_head_add(nhg_depends, depend); /* * If this is a nexthop with its own group * dependencies, add them as well. Not sure its @@ -2301,8 +2303,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* struct for nexthop group abstraction */ struct nexthop_group *nhg = NULL; struct nexthop *nh = NULL; - /* If its a group, array of nexthops */ - struct list *nhg_depends = NULL; + /* If its a group, tree head of nexthops */ + struct nhg_depends_head nhg_depends = {0}; /* Count of nexthops in group array */ int dep_count = 0; /* struct that goes into our tables */ @@ -2396,11 +2398,16 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (!nhg->nexthop) { /* Nothing to lookup */ - zebra_nhg_free_group_depends(nhg, nhg_depends); + zebra_nhg_free_group_depends(&nhg, &nhg_depends); return -1; } if (nhe) { + // TODO: Apparently we don't want changes + // to already created one in our table. + // They should be immutable... + // Gotta figure that one out. + /* This is a change to a group we already have */ @@ -2415,9 +2422,9 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else { /* This is a new nexthop group */ - nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends, + nhe = zebra_nhg_find(nhg, vrf_id, afi, id, &nhg_depends, true); - zebra_nhg_free_group_depends(nhg, nhg_depends); + nexthop_group_free_delete(&nhg); if (!nhe) { flog_err( @@ -2477,7 +2484,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } } - return 0; } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 57faca8bb4..170f7cfe64 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -66,6 +66,20 @@ const uint32_t DPLANE_DEFAULT_NEW_WORK = 100; #endif /* DPLANE_DEBUG */ +/* + * Nexthop information captured for nexthop/nexthop group updates + */ +struct dplane_nexthop_info { + uint32_t id; + afi_t afi; + vrf_id_t vrf_id; + bool is_kernel_nh; + + struct nexthop_group ng; + struct depend_info depends_info[MULTIPATH_NUM]; + uint8_t depends_count; +}; + /* * Route information captured for route updates. */ @@ -95,8 +109,8 @@ struct dplane_route_info { uint32_t zd_mtu; uint32_t zd_nexthop_mtu; - /* Nexthop hash entry */ - struct nhg_hash_entry zd_nhe; + /* Nexthop hash entry info */ + struct dplane_nexthop_info nhe; /* Nexthops */ struct nexthop_group zd_ng; @@ -470,7 +484,12 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: { - zebra_nhg_free_members(&(*pctx)->u.rinfo.zd_nhe); + if ((*pctx)->u.rinfo.nhe.ng.nexthop) { + /* This deals with recursive nexthops too */ + nexthops_free((*pctx)->u.rinfo.nhe.ng.nexthop); + + (*pctx)->u.rinfo.nhe.ng.nexthop = NULL; + } break; } @@ -1040,11 +1059,48 @@ const struct zebra_dplane_info *dplane_ctx_get_ns( } /* Accessors for nexthop information */ -const struct nhg_hash_entry * -dplane_ctx_get_nhe(const struct zebra_dplane_ctx *ctx) +uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.nhe.id; +} + +afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.nhe.afi; +} + +vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rinfo.zd_nhe); + return ctx->u.rinfo.nhe.vrf_id; +} + +bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.nhe.is_kernel_nh; +} + +const struct nexthop_group * +dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return &(ctx->u.rinfo.nhe.ng); +} + +const struct depend_info * +dplane_ctx_get_nhe_depends_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.nhe.depends_info; +} + +uint8_t dplane_ctx_get_nhe_depends_count(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.nhe.depends_count; } /* Accessors for LSP information */ @@ -1505,21 +1561,26 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; /* Copy over nhe info */ - ctx->u.rinfo.zd_nhe.id = nhe->id; - ctx->u.rinfo.zd_nhe.vrf_id = nhe->vrf_id; - ctx->u.rinfo.zd_nhe.afi = nhe->afi; - ctx->u.rinfo.zd_nhe.refcnt = nhe->refcnt; - ctx->u.rinfo.zd_nhe.is_kernel_nh = nhe->is_kernel_nh; - ctx->u.rinfo.zd_nhe.dplane_ref = nhe->dplane_ref; - ctx->u.rinfo.zd_nhe.ifp = nhe->ifp; - - ctx->u.rinfo.zd_nhe.nhg = nexthop_group_new(); - nexthop_group_copy(ctx->u.rinfo.zd_nhe.nhg, nhe->nhg); - - if (nhe->nhg_depends) - ctx->u.rinfo.zd_nhe.nhg_depends = - nhg_depend_dup_list(nhe->nhg_depends); - + ctx->u.rinfo.nhe.id = nhe->id; + ctx->u.rinfo.nhe.afi = nhe->afi; + ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id; + ctx->u.rinfo.nhe.is_kernel_nh = nhe->is_kernel_nh; + + nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg); + + if (!zebra_nhg_depends_is_empty(nhe)) { + struct nhg_depend *rb_node_dep = NULL; + uint8_t i = 0; + + RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) { + ctx->u.rinfo.nhe.depends_info[i].id = + rb_node_dep->nhe->id; + /* We aren't using weights for anything right now */ + ctx->u.rinfo.nhe.depends_info[i].weight = 0; + i++; + } + ctx->u.rinfo.nhe.depends_count = i; + } /* Extract ns info - can't use pointers to 'core' structs */ @@ -3053,7 +3114,7 @@ kernel_dplane_nexthop_update(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s", - dplane_ctx_get_nhe(ctx)->id, ctx, + dplane_ctx_get_nhe_id(ctx), ctx, dplane_op2str(dplane_ctx_get_op(ctx))); } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 6ca2a274c6..447e9c0d7f 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -276,8 +276,15 @@ const struct nexthop_group *dplane_ctx_get_old_ng( const struct zebra_dplane_ctx *ctx); /* Accessors for nexthop information */ -const struct nhg_hash_entry * -dplane_ctx_get_nhe(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx); +afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx); +vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx); +bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx); +const struct nexthop_group * +dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx); +const struct depend_info * +dplane_ctx_get_nhe_depends_info(const struct zebra_dplane_ctx *ctx); +uint8_t dplane_ctx_get_nhe_depends_count(const struct zebra_dplane_ctx *ctx); /* Accessors for LSP information */ mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 94565f434d..56f8c9d852 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -39,111 +39,133 @@ #include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra_errors.h" +#include "zebra_dplane.h" DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); -DEFINE_MTYPE_STATIC(ZEBRA, NHG_DEPENDS, "Nexthop Group Entry Depends"); +DEFINE_MTYPE_STATIC(ZEBRA, NHG_DEPEND, "Nexthop Group Dependency"); + +static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1, + const struct nhg_depend *dep2); + +RB_GENERATE(nhg_depends_head, nhg_depend, depend, zebra_nhg_depend_cmp); + +static void nhg_depend_free(struct nhg_depend *dep) +{ + XFREE(MTYPE_NHG_DEPEND, dep); +} + +static struct nhg_depend *nhg_depend_new(struct nhg_hash_entry *nhe) +{ + struct nhg_depend *new = NULL; + + new = XCALLOC(MTYPE_NHG_DEPEND, sizeof(struct nhg_depend)); + new->nhe = nhe; + + return new; +} + +static uint8_t zebra_nhg_depends_head_count(const struct nhg_depends_head *head) +{ + struct nhg_depend *rb_node_dep = NULL; + uint8_t i = 0; + + RB_FOREACH (rb_node_dep, nhg_depends_head, head) { + i++; + } + return i; +} + +uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) +{ + return zebra_nhg_depends_head_count(&nhe->nhg_depends); +} + +static bool zebra_nhg_depends_head_is_empty(const struct nhg_depends_head *head) +{ + return RB_EMPTY(nhg_depends_head, head); +} /** - * nhg_depend_add() - Add a new dependency to the nhg_hash_entry + * zebra_nhg_depends_is_empty() - Are there any dependencies * - * @nhg_depends: List we are adding the dependency to - * @depend: Dependency we are adding + * @nhe: Nexthop group hash entry * - * Return: Newly created nhg_depend + * Return: True if empty, False otherwise */ -struct nhg_depend *nhg_depend_add(struct list *nhg_depends, - struct nhg_hash_entry *depend) +bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) { - struct nhg_depend *nhg_dp = NULL; + return zebra_nhg_depends_head_is_empty(&nhe->nhg_depends); +} + +void zebra_nhg_depends_head_del(struct nhg_depends_head *head, + struct nhg_hash_entry *depend) +{ + struct nhg_depend lookup = {}; + struct nhg_depend *removed = NULL; + + lookup.nhe = depend; - nhg_dp = nhg_depend_new(); - nhg_dp->nhe = depend; + removed = RB_REMOVE(nhg_depends_head, head, &lookup); - listnode_add(nhg_depends, nhg_dp); - return nhg_dp; + nhg_depend_free(removed); } -/** - * nhg_depend_new() - Allocate a new nhg_depend struct - * - * Return: Allocated nhg_depend struct - */ -struct nhg_depend *nhg_depend_new(void) +// TODO: Refactor this for use with dependents as well +void zebra_nhg_depends_head_add(struct nhg_depends_head *head, + struct nhg_hash_entry *depend) { - return XCALLOC(MTYPE_NHG_DEPENDS, sizeof(struct nhg_depend)); + struct nhg_depend *new = NULL; + + new = nhg_depend_new(depend); + + RB_INSERT(nhg_depends_head, head, new); } /** - * nhg_depend_free() - Free the nhg_depend struct + * zebra_nhg_depend_del() - Delete a dependency from the nhg_hash_entry + * + * @from: Nexthop group hash entry we are deleting from + * @depend: Dependency we are deleting */ -void nhg_depend_free(struct nhg_depend *depend) +void zebra_nhg_depends_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *depend) { - XFREE(MTYPE_NHG_DEPENDS, depend); + zebra_nhg_depends_head_del(&from->nhg_depends, depend); } /** - * nhg_depend_new_list() - Allocate a new list for nhg_depends + * zebra_nhg_depends_add() - Add a new dependency to the nhg_hash_entry * - * Return: Allocated nhg_depend list + * @to: Nexthop group hash entry we are adding to + * @depend: Dependency we are adding */ -struct list *nhg_depend_new_list() +void zebra_nhg_depends_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *depend) { - struct list *nhg_depends = NULL; - - nhg_depends = list_new(); - nhg_depends->del = (void (*)(void *))nhg_depend_free; - - return nhg_depends; + zebra_nhg_depends_head_add(&to->nhg_depends, depend); } /** - * nhg_depend_dup_list() - Duplicate the dependency linked list + * zebra_nhg_depends_head_init() - Helper to init the RB tree head directly * - * @from: List to duplicate - * - * Return: New list + * @head: RB nhg_depends_head struct */ -struct list *nhg_depend_dup_list(struct list *from) +void zebra_nhg_depends_head_init(struct nhg_depends_head *head) { - struct list *to = NULL; - struct listnode *ln = NULL; - struct nhg_depend *n_dp = NULL; - - to = nhg_depend_new_list(); - - for (ALL_LIST_ELEMENTS_RO(from, ln, n_dp)) { - nhg_depend_add(to, n_dp->nhe); - } - - return to; + RB_INIT(nhg_depends_head, head); } /** - * zebra_nhg_depends_lookup_id() - Lookup for an id in the nhg_depends - * linked list of another nhe + * zebra_nhg_depends_init() - Initialize tree for nhg dependencies * - * @nhe: Nexthop group hash entry with list to look in - * @lookup: ID to look for - * - * Return: Nexthop group hash entry if found + * @nhe: Nexthop group hash entry */ -static struct nhg_hash_entry * -zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id) +void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) { - struct listnode *ln = NULL; - struct nhg_depend *n_dp = NULL; - struct nhg_hash_entry *match = NULL; - - for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, ln, n_dp)) { - if (n_dp->nhe->id == id) { - match = n_dp->nhe; - break; - } - } - - return match; + zebra_nhg_depends_head_init(&nhe->nhg_depends); } + /** * zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal * @@ -158,21 +180,20 @@ zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id) static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1, const struct nhg_hash_entry *nhe2) { - struct listnode *ln = NULL; - struct nhg_depend *n_dp = NULL; + struct nhg_depend *rb_node_dep = NULL; - if (!nhe1->nhg_depends && !nhe2->nhg_depends) + if (zebra_nhg_depends_is_empty(nhe1) + && zebra_nhg_depends_is_empty(nhe2)) return true; - if ((nhe1->nhg_depends && !nhe2->nhg_depends) - || (nhe2->nhg_depends && !nhe1->nhg_depends)) - return false; - - if (listcount(nhe1->nhg_depends) != listcount(nhe2->nhg_depends)) + if ((zebra_nhg_depends_is_empty(nhe1) + && !zebra_nhg_depends_is_empty(nhe2)) + || (zebra_nhg_depends_is_empty(nhe2) + && !zebra_nhg_depends_is_empty(nhe1))) return false; - for (ALL_LIST_ELEMENTS_RO(nhe1->nhg_depends, ln, n_dp)) { - if (!zebra_nhg_depends_lookup_id(nhe2, n_dp->nhe->id)) + RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe1->nhg_depends) { + if (!RB_FIND(nhg_depends_head, &nhe2->nhg_depends, rb_node_dep)) return false; } @@ -188,7 +209,7 @@ static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1, */ struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id) { - struct nhg_hash_entry lookup = {0}; + struct nhg_hash_entry lookup = {}; lookup.id = id; return hash_lookup(zrouter.nhgs_id, &lookup); @@ -227,10 +248,7 @@ static void *zebra_nhg_alloc(void *arg) nhe->id = copy->id; - nhe->nhg_depends = NULL; - - if (copy->nhg_depends) - nhe->nhg_depends = nhg_depend_dup_list(copy->nhg_depends); + nhe->nhg_depends = copy->nhg_depends; nhe->nhg = nexthop_group_new(); nexthop_group_copy(nhe->nhg, copy->nhg); @@ -254,42 +272,6 @@ static void *zebra_nhg_alloc(void *arg) return nhe; } -static uint32_t zebra_nhg_hash_key_nexthop_group(struct nexthop_group *nhg) -{ - struct nexthop *nh; - uint32_t i; - uint32_t key = 0; - - /* - * We are not interested in hashing over any recursively - * resolved nexthops - */ - for (nh = nhg->nexthop; nh; nh = nh->next) { - key = jhash_1word(nh->type, key); - key = jhash_2words(nh->vrf_id, nh->nh_label_type, key); - /* gate and blackhole are together in a union */ - key = jhash(&nh->gate, sizeof(nh->gate), key); - key = jhash(&nh->src, sizeof(nh->src), key); - key = jhash(&nh->rmap_src, sizeof(nh->rmap_src), key); - if (nh->nh_label) { - for (i = 0; i < nh->nh_label->num_labels; i++) - key = jhash_1word(nh->nh_label->label[i], key); - } - switch (nh->type) { - case NEXTHOP_TYPE_IPV4_IFINDEX: - case NEXTHOP_TYPE_IPV6_IFINDEX: - case NEXTHOP_TYPE_IFINDEX: - key = jhash_1word(nh->ifindex, key); - break; - case NEXTHOP_TYPE_BLACKHOLE: - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV6: - break; - } - } - return key; -} - uint32_t zebra_nhg_hash_key(const void *arg) { const struct nhg_hash_entry *nhe = arg; @@ -298,7 +280,7 @@ uint32_t zebra_nhg_hash_key(const void *arg) key = jhash_2words(nhe->vrf_id, nhe->afi, key); - key = jhash_1word(zebra_nhg_hash_key_nexthop_group(nhe->nhg), key); + key = jhash_1word(nexthop_group_hash(nhe->nhg), key); return key; } @@ -335,6 +317,31 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } +/** + * zebra_nhg_cmp() - Compare the ID's of two nhe's + * + * @nhe1: Nexthop group hash entry #1 + * @nhe2: Nexthop group hash entry #2 + * + * Return: + * - Negative: #1 < #2 + * - Positive: #1 > #2 + * - Zero: #1 = #2 + * + * This is used in the nhg RB trees. + */ +static int zebra_nhg_cmp(const struct nhg_hash_entry *nhe1, + const struct nhg_hash_entry *nhe2) +{ + return nhe1->id - nhe2->id; +} + +static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1, + const struct nhg_depend *dep2) +{ + return zebra_nhg_cmp(dep1->nhe, dep2->nhe); +} + /** * zebra_nhg_find() - Find the zebra nhg in our table, or create it * @@ -344,7 +351,7 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) * @id: ID we lookup with, 0 means its from us and we * need to give it an ID, otherwise its from the * kernel as we use the ID it gave us. - * @nhg_depends: Nexthop dependencies + * @nhg_depends: Nexthop dependency tree head * @is_kernel_nh: Was the nexthop created by the kernel * * Return: Hash entry found or created @@ -368,7 +375,7 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) */ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi, uint32_t id, - struct list *nhg_depends, + struct nhg_depends_head *nhg_depends, bool is_kernel_nh) { /* lock for getiing and setting the id */ @@ -376,7 +383,7 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, /* id counter to keep in sync with kernel */ static uint32_t id_counter = 0; - struct nhg_hash_entry lookup = {0}; + struct nhg_hash_entry lookup = {}; struct nhg_hash_entry *nhe = NULL; uint32_t old_id_counter = 0; @@ -399,7 +406,7 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, lookup.vrf_id = vrf_id; lookup.afi = afi; lookup.nhg = nhg; - lookup.nhg_depends = nhg_depends; + lookup.nhg_depends = *nhg_depends; lookup.is_kernel_nh = is_kernel_nh; if (id) @@ -442,23 +449,34 @@ struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi) return nhe; } +void zebra_nhg_depends_free(struct nhg_depends_head *head) +{ + struct nhg_depend *rb_node_dep = NULL; + struct nhg_depend *tmp = NULL; + + if (!zebra_nhg_depends_head_is_empty(head)) { + RB_FOREACH_SAFE (rb_node_dep, nhg_depends_head, head, tmp) { + RB_REMOVE(nhg_depends_head, head, rb_node_dep); + nhg_depend_free(rb_node_dep); + } + } +} + /** * zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group * struct and depends * - * @nhg: Nexthop group - * @nhg_depends: Nexthop group hash entry dependency list + * @nhg: Nexthop_group + * @nhg_depends: Nexthop group dependency tree head */ -void zebra_nhg_free_group_depends(struct nexthop_group *nhg, - struct list *nhg_depends) +void zebra_nhg_free_group_depends(struct nexthop_group **nhg, + struct nhg_depends_head *head) { - if (nhg_depends) - list_delete(&nhg_depends); - if (nhg) { - if (nhg->nexthop) - nexthops_free(nhg->nexthop); - nexthop_group_delete(&nhg); - } + if (head) + zebra_nhg_depends_free(head); + + if (nhg) + nexthop_group_free_delete(nhg); } /** @@ -470,7 +488,7 @@ void zebra_nhg_free_group_depends(struct nexthop_group *nhg, */ void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { - zebra_nhg_free_group_depends(nhe->nhg, nhe->nhg_depends); + zebra_nhg_free_group_depends(&nhe->nhg, &nhe->nhg_depends); } /** @@ -525,12 +543,11 @@ static void zebra_nhg_uninstall_release(struct nhg_hash_entry *nhe) */ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) { - if (nhe->nhg_depends) { - struct listnode *ln = NULL; - struct nhg_depend *n_dp = NULL; + if (!zebra_nhg_depends_is_empty(nhe)) { + struct nhg_depend *rb_node_dep = NULL; - for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, ln, n_dp)) { - zebra_nhg_decrement_ref(n_dp->nhe); + RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) { + zebra_nhg_decrement_ref(rb_node_dep->nhe); } } @@ -548,12 +565,11 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) */ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) { - if (nhe->nhg_depends) { - struct listnode *ln = NULL; - struct nhg_depend *n_dp = NULL; + if (!zebra_nhg_depends_is_empty(nhe)) { + struct nhg_depend *rb_node_dep = NULL; - for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, ln, n_dp)) { - zebra_nhg_increment_ref(n_dp->nhe); + RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) { + zebra_nhg_increment_ref(rb_node_dep->nhe); } } @@ -1177,7 +1193,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) op = dplane_ctx_get_op(ctx); status = dplane_ctx_get_status(ctx); - id = dplane_ctx_get_nhe(ctx)->id; + id = dplane_ctx_get_nhe_id(ctx); nhe = zebra_nhg_lookup_id(id); if (nhe) { diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 90c7abb3e6..1cc1c47e32 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -28,6 +28,18 @@ #include "zebra/zebra_dplane.h" +/* This struct is used exclusively for dataplane + * interaction via a dataplane context. + * + * It is designed to mimic the netlink nexthop_grp + * struct in include/linux/nexthop.h + */ +struct depend_info { + uint32_t id; + uint8_t weight; +}; + + struct nhg_hash_entry { uint32_t id; afi_t afi; @@ -49,12 +61,15 @@ struct nhg_hash_entry { uint32_t flags; - /* Dependency list for other entries. + /* Dependency tree for other entries. * For instance a group with two * nexthops will have two dependencies * pointing to those nhg_hash_entries. + * + * Using a rb tree here to make lookups + * faster with ID's. */ - struct list *nhg_depends; + RB_HEAD(nhg_depends_head, nhg_depend) nhg_depends; /* * Is this nexthop group valid, ie all nexthops are fully resolved. * What is fully resolved? It's a nexthop that is either self contained @@ -75,22 +90,32 @@ struct nhg_hash_entry { #define NEXTHOP_GROUP_QUEUED 0x4 }; -/* Struct for dependency nexthop */ +/* Abstraction for dependency tree */ struct nhg_depend { + RB_ENTRY(nhg_depend) depend; struct nhg_hash_entry *nhe; }; +RB_PROTOTYPE(nhg_depends_head, nhg_depend, depend, zebra_nhg_depend_cmp); void zebra_nhg_init(void); void zebra_nhg_terminate(void); -extern struct nhg_depend *nhg_depend_add(struct list *nhg_depends, - struct nhg_hash_entry *depend); -extern struct nhg_depend *nhg_depend_new(void); -extern void nhg_depend_free(struct nhg_depend *depends); +extern uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); +extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe); +extern void zebra_nhg_depends_head_del(struct nhg_depends_head *head, + struct nhg_hash_entry *depend); +extern void zebra_nhg_depends_head_add(struct nhg_depends_head *head, + struct nhg_hash_entry *depend); +extern void zebra_nhg_depends_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *depend); +extern void zebra_nhg_depends_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *depend); +extern void zebra_nhg_depends_head_init(struct nhg_depends_head *head); +extern void zebra_nhg_depends_init(struct nhg_hash_entry *nhe); +extern void zebra_nhg_depends_copy(struct nhg_hash_entry *to, + struct nhg_hash_entry *from); -extern struct list *nhg_depend_new_list(void); -extern struct list *nhg_depend_dup_list(struct list *from); extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id); extern int zebra_nhg_insert_id(struct nhg_hash_entry *nhe); @@ -103,13 +128,16 @@ extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); extern struct nhg_hash_entry * zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi, - uint32_t id, struct list *nhg_depends, bool is_kernel_nh); + uint32_t id, struct nhg_depends_head *nhg_depends, + bool is_kernel_nh); extern struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi); -void zebra_nhg_free_group_depends(struct nexthop_group *nhg, - struct list *nhg_depends); + +void zebra_nhg_depends_free(struct nhg_depends_head *head); +void zebra_nhg_free_group_depends(struct nexthop_group **nhg, + struct nhg_depends_head *head); void zebra_nhg_free_members(struct nhg_hash_entry *nhe); void zebra_nhg_free(void *arg); void zebra_nhg_release(struct nhg_hash_entry *nhe); @@ -123,5 +151,7 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); void zebra_nhg_cleanup_tables(void); +/* Forward ref of dplane update context type */ +struct zebra_dplane_ctx; void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx); #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 3155570df5..957b7e14f4 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2638,7 +2638,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_node *rn; struct route_entry *same = NULL; struct nhg_hash_entry *nhe = NULL; - struct list *nhg_depends = NULL; + struct nhg_depends_head nhg_depends = {0}; /* Default to route afi */ afi_t nhg_afi = afi; int ret = 0; @@ -2651,7 +2651,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { - zebra_nhg_free_group_depends(re->ng, nhg_depends); + nexthop_group_free_delete(&re->ng); XFREE(MTYPE_RE, re); return 0; } @@ -2667,7 +2667,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct nexthop lookup = {0}; struct nhg_hash_entry *depend = NULL; - nhg_depends = nhg_depend_new_list(); + zebra_nhg_depends_head_init(&nhg_depends); for (ALL_NEXTHOPS_PTR(re->ng, nh)) { lookup = *nh; @@ -2675,20 +2675,21 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, lookup.next = NULL; /* Use the route afi here, since a single nh */ depend = zebra_nhg_find_nexthop(&lookup, afi); - nhg_depend_add(nhg_depends, depend); + zebra_nhg_depends_head_add(&nhg_depends, depend); } /* change the afi for group */ - if (listcount(nhg_depends)) - nhg_afi = AFI_UNSPEC; + nhg_afi = AFI_UNSPEC; } + // TODO: Add proto type here nhe = zebra_nhg_find(re->ng, re->vrf_id, nhg_afi, re->nhe_id, - nhg_depends, false); + &nhg_depends, false); if (nhe) { - // TODO: Add interface pointer - zebra_nhg_free_group_depends(re->ng, nhg_depends); + /* It should point to the nhe nexthop group now */ + if (re->ng) + nexthop_group_free_delete(&re->ng); re->ng = nhe->nhg; re->nhe_id = nhe->id; zebra_nhg_increment_ref(nhe); @@ -2697,6 +2698,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, EC_ZEBRA_TABLE_LOOKUP_FAILED, "Zebra failed to find or create a nexthop hash entry for id=%u in a route entry", re->nhe_id); + zebra_nhg_depends_free(&nhg_depends); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c2a9d091d2..106cd6b027 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1127,13 +1127,13 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, vty_out(vty, "\tInterface Index: %d\n", nhe->ifp->ifindex); - if (nhe->nhg_depends) { - struct listnode *dp_node = NULL; - struct nhg_depend *n_dp = NULL; + if (!zebra_nhg_depends_is_empty(nhe)) { + struct nhg_depend *rb_node_dep = NULL; + vty_out(vty, "\tDepends:"); - for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, dp_node, - n_dp)) { - vty_out(vty, " (%u)", n_dp->nhe->id); + RB_FOREACH (rb_node_dep, nhg_depends_head, + &nhe->nhg_depends) { + vty_out(vty, " (%u)", rb_node_dep->nhe->id); } vty_out(vty, "\n"); } -- cgit v1.2.3 From a15d4c0089a6b8f59932df39357725feadfb9f91 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 13 May 2019 18:13:02 -0700 Subject: zebra: Abstract the RB nodes/add dependents tree Create a nhg_depenents tree that will function as a way to get back pointers for NHE's depending on it. Abstract the RB nodes into nhg_connected for both depends and dependents. This same struct is used for both. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 11 ++-- zebra/zebra_dplane.c | 5 +- zebra/zebra_nhg.c | 170 +++++++++++++++++++++++++++++++-------------------- zebra/zebra_nhg.h | 31 ++++++---- zebra/zebra_rib.c | 8 +-- zebra/zebra_vty.c | 12 +++- 6 files changed, 146 insertions(+), 91 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f7e72e243f..bdf613cef4 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2225,14 +2225,14 @@ static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb, * netlink_nexthop_process_group() - Iterate over nhmsg nexthop group * * @tb: Netlink RTA data - * @nhg_depends: Tree head of nexthops in the group (depends) + * @nhg_depends: Tree head of nexthops in the group * @nhg: Nexthop group struct * * Return: Count of nexthops in the group */ static int netlink_nexthop_process_group(struct rtattr **tb, struct nexthop_group *nhg, - struct nhg_depends_head *nhg_depends) + struct nhg_connected_head *nhg_depends) { int count = 0; struct nexthop_grp *n_grp = NULL; @@ -2251,7 +2251,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, zlog_debug("Nexthop group type: %d", *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); - zebra_nhg_depends_head_init(nhg_depends); + zebra_nhg_connected_head_init(nhg_depends); for (int i = 0; i < count; i++) { /* We do not care about nexthop_grp.weight at @@ -2261,7 +2261,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, */ depend = zebra_nhg_lookup_id(n_grp[i].id); if (depend) { - zebra_nhg_depends_head_add(nhg_depends, depend); + zebra_nhg_connected_head_add(nhg_depends, depend); /* * If this is a nexthop with its own group * dependencies, add them as well. Not sure its @@ -2304,7 +2304,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct nexthop_group *nhg = NULL; struct nexthop *nh = NULL; /* If its a group, tree head of nexthops */ - struct nhg_depends_head nhg_depends = {0}; + struct nhg_connected_head nhg_depends = {0}; /* Count of nexthops in group array */ int dep_count = 0; /* struct that goes into our tables */ @@ -2449,6 +2449,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) EC_ZEBRA_DUPLICATE_NHG_MESSAGE, "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring", id); + zebra_nhg_connected_head_free(&nhg_depends); } } if (ifp) { diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 170f7cfe64..e4890319d9 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1569,10 +1569,11 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg); if (!zebra_nhg_depends_is_empty(nhe)) { - struct nhg_depend *rb_node_dep = NULL; + struct nhg_connected *rb_node_dep = NULL; uint8_t i = 0; - RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) { + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends) { ctx->u.rinfo.nhe.depends_info[i].id = rb_node_dep->nhe->id; /* We aren't using weights for anything right now */ diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 56f8c9d852..d3204bdf48 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -42,34 +42,35 @@ #include "zebra_dplane.h" DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); -DEFINE_MTYPE_STATIC(ZEBRA, NHG_DEPEND, "Nexthop Group Dependency"); +DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected"); -static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1, - const struct nhg_depend *dep2); +static int zebra_nhg_connected_cmp(const struct nhg_connected *dep1, + const struct nhg_connected *dep2); -RB_GENERATE(nhg_depends_head, nhg_depend, depend, zebra_nhg_depend_cmp); +RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, + zebra_nhg_connected_cmp); -static void nhg_depend_free(struct nhg_depend *dep) +static void nhg_connected_free(struct nhg_connected *dep) { - XFREE(MTYPE_NHG_DEPEND, dep); + XFREE(MTYPE_NHG_CONNECTED, dep); } -static struct nhg_depend *nhg_depend_new(struct nhg_hash_entry *nhe) +static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) { - struct nhg_depend *new = NULL; + struct nhg_connected *new = NULL; - new = XCALLOC(MTYPE_NHG_DEPEND, sizeof(struct nhg_depend)); + new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected)); new->nhe = nhe; return new; } -static uint8_t zebra_nhg_depends_head_count(const struct nhg_depends_head *head) +static uint8_t zebra_nhg_connected_count(const struct nhg_connected_head *head) { - struct nhg_depend *rb_node_dep = NULL; + struct nhg_connected *rb_node_dep = NULL; uint8_t i = 0; - RB_FOREACH (rb_node_dep, nhg_depends_head, head) { + RB_FOREACH (rb_node_dep, nhg_connected_head, head) { i++; } return i; @@ -77,52 +78,69 @@ static uint8_t zebra_nhg_depends_head_count(const struct nhg_depends_head *head) uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) { - return zebra_nhg_depends_head_count(&nhe->nhg_depends); + return zebra_nhg_connected_count(&nhe->nhg_depends); } -static bool zebra_nhg_depends_head_is_empty(const struct nhg_depends_head *head) +static bool +zebra_nhg_connected_head_is_empty(const struct nhg_connected_head *head) { - return RB_EMPTY(nhg_depends_head, head); + return RB_EMPTY(nhg_connected_head, head); } -/** - * zebra_nhg_depends_is_empty() - Are there any dependencies - * - * @nhe: Nexthop group hash entry - * - * Return: True if empty, False otherwise - */ bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) { - return zebra_nhg_depends_head_is_empty(&nhe->nhg_depends); + return zebra_nhg_connected_head_is_empty(&nhe->nhg_depends); } -void zebra_nhg_depends_head_del(struct nhg_depends_head *head, - struct nhg_hash_entry *depend) +void zebra_nhg_connected_head_del(struct nhg_connected_head *head, + struct nhg_hash_entry *depend) { - struct nhg_depend lookup = {}; - struct nhg_depend *removed = NULL; + struct nhg_connected lookup = {}; + struct nhg_connected *removed = NULL; lookup.nhe = depend; - removed = RB_REMOVE(nhg_depends_head, head, &lookup); + removed = RB_REMOVE(nhg_connected_head, head, &lookup); - nhg_depend_free(removed); + nhg_connected_free(removed); } -// TODO: Refactor this for use with dependents as well -void zebra_nhg_depends_head_add(struct nhg_depends_head *head, - struct nhg_hash_entry *depend) +void zebra_nhg_connected_head_add(struct nhg_connected_head *head, + struct nhg_hash_entry *depend) { - struct nhg_depend *new = NULL; + struct nhg_connected *new = NULL; + + new = nhg_connected_new(depend); + + RB_INSERT(nhg_connected_head, head, new); +} - new = nhg_depend_new(depend); +/** + * zebra_nhg_dependents_del() - Delete a dependent from the nhg_hash_entry + * + * @from: Nexthop group hash entry we are deleting from + * @dependent: Dependent we are deleting + */ +void zebra_nhg_dependents_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *dependent) +{ + zebra_nhg_connected_head_del(&from->nhg_dependents, dependent); +} - RB_INSERT(nhg_depends_head, head, new); +/** + * zebra_nhg_dependents_add() - Add a new dependent to the nhg_hash_entry + * + * @to: Nexthop group hash entry we are adding to + * @dependent: Dependent we are adding + */ +void zebra_nhg_dependents_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *dependent) +{ + zebra_nhg_connected_head_add(&to->nhg_dependents, dependent); } /** - * zebra_nhg_depend_del() - Delete a dependency from the nhg_hash_entry + * zebra_nhg_depends_del() - Delete a dependency from the nhg_hash_entry * * @from: Nexthop group hash entry we are deleting from * @depend: Dependency we are deleting @@ -130,7 +148,10 @@ void zebra_nhg_depends_head_add(struct nhg_depends_head *head, void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend) { - zebra_nhg_depends_head_del(&from->nhg_depends, depend); + zebra_nhg_connected_head_del(&from->nhg_depends, depend); + + /* Delete from the dependent tree */ + zebra_nhg_dependents_del(depend, from); } /** @@ -142,17 +163,12 @@ void zebra_nhg_depends_del(struct nhg_hash_entry *from, void zebra_nhg_depends_add(struct nhg_hash_entry *to, struct nhg_hash_entry *depend) { - zebra_nhg_depends_head_add(&to->nhg_depends, depend); + zebra_nhg_connected_head_add(&to->nhg_depends, depend); } -/** - * zebra_nhg_depends_head_init() - Helper to init the RB tree head directly - * - * @head: RB nhg_depends_head struct - */ -void zebra_nhg_depends_head_init(struct nhg_depends_head *head) +void zebra_nhg_connected_head_init(struct nhg_connected_head *head) { - RB_INIT(nhg_depends_head, head); + RB_INIT(nhg_connected_head, head); } /** @@ -162,7 +178,7 @@ void zebra_nhg_depends_head_init(struct nhg_depends_head *head) */ void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) { - zebra_nhg_depends_head_init(&nhe->nhg_depends); + zebra_nhg_connected_head_init(&nhe->nhg_depends); } @@ -180,7 +196,7 @@ void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1, const struct nhg_hash_entry *nhe2) { - struct nhg_depend *rb_node_dep = NULL; + struct nhg_connected *rb_node_dep = NULL; if (zebra_nhg_depends_is_empty(nhe1) && zebra_nhg_depends_is_empty(nhe2)) @@ -192,8 +208,9 @@ static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1, && !zebra_nhg_depends_is_empty(nhe1))) return false; - RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe1->nhg_depends) { - if (!RB_FIND(nhg_depends_head, &nhe2->nhg_depends, rb_node_dep)) + RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe1->nhg_depends) { + if (!RB_FIND(nhg_connected_head, &nhe2->nhg_depends, + rb_node_dep)) return false; } @@ -242,6 +259,8 @@ static void *zebra_nhg_alloc(void *arg) { struct nhg_hash_entry *nhe; struct nhg_hash_entry *copy = arg; + struct nhg_connected *rb_node_dep = NULL; + nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry)); @@ -260,6 +279,13 @@ static void *zebra_nhg_alloc(void *arg) nhe->dplane_ref = zebra_router_get_next_sequence(); nhe->ifp = NULL; + /* Attach backpointer to anything that it depends on */ + if (!zebra_nhg_depends_is_empty(nhe)) { + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends) { + zebra_nhg_dependents_add(rb_node_dep->nhe, nhe); + } + } /* Add to id table as well */ zebra_nhg_insert_id(nhe); @@ -336,8 +362,8 @@ static int zebra_nhg_cmp(const struct nhg_hash_entry *nhe1, return nhe1->id - nhe2->id; } -static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1, - const struct nhg_depend *dep2) +static int zebra_nhg_connected_cmp(const struct nhg_connected *dep1, + const struct nhg_connected *dep2) { return zebra_nhg_cmp(dep1->nhe, dep2->nhe); } @@ -375,7 +401,7 @@ static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1, */ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi, uint32_t id, - struct nhg_depends_head *nhg_depends, + struct nhg_connected_head *nhg_depends, bool is_kernel_nh) { /* lock for getiing and setting the id */ @@ -449,15 +475,15 @@ struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi) return nhe; } -void zebra_nhg_depends_free(struct nhg_depends_head *head) +void zebra_nhg_connected_head_free(struct nhg_connected_head *head) { - struct nhg_depend *rb_node_dep = NULL; - struct nhg_depend *tmp = NULL; + struct nhg_connected *rb_node_dep = NULL; + struct nhg_connected *tmp = NULL; - if (!zebra_nhg_depends_head_is_empty(head)) { - RB_FOREACH_SAFE (rb_node_dep, nhg_depends_head, head, tmp) { - RB_REMOVE(nhg_depends_head, head, rb_node_dep); - nhg_depend_free(rb_node_dep); + if (!zebra_nhg_connected_head_is_empty(head)) { + RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) { + RB_REMOVE(nhg_connected_head, head, rb_node_dep); + nhg_connected_free(rb_node_dep); } } } @@ -470,10 +496,19 @@ void zebra_nhg_depends_free(struct nhg_depends_head *head) * @nhg_depends: Nexthop group dependency tree head */ void zebra_nhg_free_group_depends(struct nexthop_group **nhg, - struct nhg_depends_head *head) + struct nhg_connected_head *head) { + // TODO + // + // + // FIX THIS NAMING + // + // + // + // + // if (head) - zebra_nhg_depends_free(head); + zebra_nhg_connected_head_free(head); if (nhg) nexthop_group_free_delete(nhg); @@ -489,6 +524,9 @@ void zebra_nhg_free_group_depends(struct nexthop_group **nhg, void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { zebra_nhg_free_group_depends(&nhe->nhg, &nhe->nhg_depends); + + // TODO: Fixup this function + zebra_nhg_connected_head_free(&nhe->nhg_dependents); } /** @@ -544,9 +582,10 @@ static void zebra_nhg_uninstall_release(struct nhg_hash_entry *nhe) void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) { if (!zebra_nhg_depends_is_empty(nhe)) { - struct nhg_depend *rb_node_dep = NULL; + struct nhg_connected *rb_node_dep = NULL; - RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) { + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends) { zebra_nhg_decrement_ref(rb_node_dep->nhe); } } @@ -566,9 +605,10 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) { if (!zebra_nhg_depends_is_empty(nhe)) { - struct nhg_depend *rb_node_dep = NULL; + struct nhg_connected *rb_node_dep = NULL; - RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) { + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends) { zebra_nhg_increment_ref(rb_node_dep->nhe); } } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 1cc1c47e32..4aa59e7530 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -69,7 +69,7 @@ struct nhg_hash_entry { * Using a rb tree here to make lookups * faster with ID's. */ - RB_HEAD(nhg_depends_head, nhg_depend) nhg_depends; + RB_HEAD(nhg_connected_head, nhg_connected) nhg_depends, nhg_dependents; /* * Is this nexthop group valid, ie all nexthops are fully resolved. * What is fully resolved? It's a nexthop that is either self contained @@ -90,28 +90,33 @@ struct nhg_hash_entry { #define NEXTHOP_GROUP_QUEUED 0x4 }; -/* Abstraction for dependency tree */ -struct nhg_depend { - RB_ENTRY(nhg_depend) depend; +/* Abstraction for connected trees */ +struct nhg_connected { + RB_ENTRY(nhg_connected) nhg_entry; struct nhg_hash_entry *nhe; }; -RB_PROTOTYPE(nhg_depends_head, nhg_depend, depend, zebra_nhg_depend_cmp); +RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, + zebra_nhg_connected_cmp); void zebra_nhg_init(void); void zebra_nhg_terminate(void); extern uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe); -extern void zebra_nhg_depends_head_del(struct nhg_depends_head *head, - struct nhg_hash_entry *depend); -extern void zebra_nhg_depends_head_add(struct nhg_depends_head *head, - struct nhg_hash_entry *depend); +extern void zebra_nhg_connected_head_del(struct nhg_connected_head *head, + struct nhg_hash_entry *nhe); +extern void zebra_nhg_connected_head_add(struct nhg_connected_head *head, + struct nhg_hash_entry *nhe); +extern void zebra_nhg_dependents_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *dependent); +extern void zebra_nhg_dependents_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *dependent); extern void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend); extern void zebra_nhg_depends_add(struct nhg_hash_entry *to, struct nhg_hash_entry *depend); -extern void zebra_nhg_depends_head_init(struct nhg_depends_head *head); +extern void zebra_nhg_connected_head_init(struct nhg_connected_head *head); extern void zebra_nhg_depends_init(struct nhg_hash_entry *nhe); extern void zebra_nhg_depends_copy(struct nhg_hash_entry *to, struct nhg_hash_entry *from); @@ -128,16 +133,16 @@ extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); extern struct nhg_hash_entry * zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi, - uint32_t id, struct nhg_depends_head *nhg_depends, + uint32_t id, struct nhg_connected_head *nhg_depends, bool is_kernel_nh); extern struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi); -void zebra_nhg_depends_free(struct nhg_depends_head *head); +void zebra_nhg_connected_head_free(struct nhg_connected_head *head); void zebra_nhg_free_group_depends(struct nexthop_group **nhg, - struct nhg_depends_head *head); + struct nhg_connected_head *head); void zebra_nhg_free_members(struct nhg_hash_entry *nhe); void zebra_nhg_free(void *arg); void zebra_nhg_release(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 957b7e14f4..7015ff77de 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2638,7 +2638,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_node *rn; struct route_entry *same = NULL; struct nhg_hash_entry *nhe = NULL; - struct nhg_depends_head nhg_depends = {0}; + struct nhg_connected_head nhg_depends = {0}; /* Default to route afi */ afi_t nhg_afi = afi; int ret = 0; @@ -2667,7 +2667,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct nexthop lookup = {0}; struct nhg_hash_entry *depend = NULL; - zebra_nhg_depends_head_init(&nhg_depends); + zebra_nhg_connected_head_init(&nhg_depends); for (ALL_NEXTHOPS_PTR(re->ng, nh)) { lookup = *nh; @@ -2675,7 +2675,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, lookup.next = NULL; /* Use the route afi here, since a single nh */ depend = zebra_nhg_find_nexthop(&lookup, afi); - zebra_nhg_depends_head_add(&nhg_depends, depend); + zebra_nhg_connected_head_add(&nhg_depends, depend); } /* change the afi for group */ @@ -2698,7 +2698,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, EC_ZEBRA_TABLE_LOOKUP_FAILED, "Zebra failed to find or create a nexthop hash entry for id=%u in a route entry", re->nhe_id); - zebra_nhg_depends_free(&nhg_depends); + zebra_nhg_connected_head_free(&nhg_depends); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 106cd6b027..cd099da37e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1111,6 +1111,7 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) { struct nexthop *nhop; + struct nhg_connected *rb_node_dep = NULL; if (afi && nhe->afi != afi) continue; @@ -1128,14 +1129,21 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, nhe->ifp->ifindex); if (!zebra_nhg_depends_is_empty(nhe)) { - struct nhg_depend *rb_node_dep = NULL; vty_out(vty, "\tDepends:"); - RB_FOREACH (rb_node_dep, nhg_depends_head, + RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe->nhg_depends) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); } vty_out(vty, "\n"); + + } else { + vty_out(vty, "\tDependents:"); + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_dependents) { + vty_out(vty, " (%u)", rb_node_dep->nhe->id); + } + vty_out(vty, "\n"); } for (ALL_NEXTHOPS_PTR(nhe->nhg, nhop)) { -- cgit v1.2.3 From fe593b781d8a927bd496c77799312cc64a565141 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 09:53:19 -0700 Subject: zebra: Re-organize/expose nhg_connected Re-organize and expose the nhg_connected functions so that it can be used outside zebra_nhg.c. And then abstract those into zebra_nhg_depends_* and zebra_nhg_depenents_* functons. Switch the ifp struct to use an RB tree for its dependents, making use of the nhg_connected functions. Signed-off-by: Stephen Worley --- zebra/interface.c | 105 +++++++++++++++-------------- zebra/interface.h | 22 +++--- zebra/rt_netlink.c | 41 ++++++------ zebra/zebra_nhg.c | 193 +++++++++++++++++++++++++++++++---------------------- zebra/zebra_nhg.h | 47 ++++++++----- zebra/zebra_rib.c | 6 +- 6 files changed, 232 insertions(+), 182 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/interface.c b/zebra/interface.c index 3eb0e68537..8fe7af3f2a 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -53,7 +53,6 @@ #include "zebra/zebra_errors.h" DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information") -DEFINE_MTYPE_STATIC(ZEBRA, NHE_CONNECTED, "Nexthops Connected") #define ZEBRA_PTM_SUPPORT @@ -108,6 +107,17 @@ static void zebra_if_node_destroy(route_table_delegate_t *delegate, route_node_destroy(delegate, table, node); } +static void zebra_if_nhg_dependents_free(struct zebra_if *zebra_if) +{ + nhg_connected_head_free(&zebra_if->nhg_dependents); +} + +static void zebra_if_nhg_dependents_init(struct zebra_if *zebra_if) +{ + nhg_connected_head_init(&zebra_if->nhg_dependents); +} + + route_table_delegate_t zebra_if_table_delegate = { .create_node = route_node_create, .destroy_node = zebra_if_node_destroy}; @@ -122,8 +132,7 @@ static int if_zebra_new_hook(struct interface *ifp) zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC; zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF; - zebra_if->nhe_connected = list_new(); - zebra_if->nhe_connected->del = (void (*)(void *))nhe_connected_free; + zebra_if_nhg_dependents_init(zebra_if); zebra_ptm_if_init(zebra_if); @@ -201,9 +210,10 @@ static int if_zebra_delete_hook(struct interface *ifp) list_delete(&rtadv->AdvDNSSLList); #endif /* HAVE_RTADV */ - list_delete(&zebra_if->nhe_connected); + zebra_if_nhg_dependents_free(zebra_if); XFREE(MTYPE_TMP, zebra_if->desc); + THREAD_OFF(zebra_if->speed_update); XFREE(MTYPE_ZINFO, zebra_if); @@ -932,48 +942,48 @@ static void if_down_del_nbr_connected(struct interface *ifp) } } -/** - * nhe_connected_add() - Add the nexthop entry to the interfaces connected list - * - * @ifp: Interface to add to - * @nhe: Nexthop hash entry to add - * - * Return: nhe_connected struct created and added - */ -struct nhe_connected *nhe_connected_add(struct interface *ifp, - struct nhg_hash_entry *nhe) +void if_nhg_dependents_add(struct interface *ifp, struct nhg_hash_entry *nhe) { - struct nhe_connected *if_nhec = NULL; - struct zebra_if *zif = (struct zebra_if *)ifp->info; + if (ifp->info) { + struct zebra_if *zif = (struct zebra_if *)ifp->info; - if_nhec = nhe_connected_new(); + nhg_connected_head_add(&zif->nhg_dependents, nhe); + } +} - /* Attach the nhe */ - if_nhec->nhe = nhe; +void if_nhg_dependents_del(struct interface *ifp, struct nhg_hash_entry *nhe) +{ + if (ifp->info) { + struct zebra_if *zif = (struct zebra_if *)ifp->info; - /* Add connected nexthop to the interface */ - listnode_add(zif->nhe_connected, if_nhec); - return if_nhec; + nhg_connected_head_del(&zif->nhg_dependents, nhe); + } } -/** - * nhe_connected() - Allocate nhe connected structure - * - * Return: Allocated nhe_connected structure - */ -struct nhe_connected *nhe_connected_new(void) +unsigned int if_nhg_dependents_count(const struct interface *ifp) { - return XCALLOC(MTYPE_NHE_CONNECTED, sizeof(struct nhe_connected)); + if (ifp->info) { + struct zebra_if *zif = (struct zebra_if *)ifp->info; + + return nhg_connected_head_count(&zif->nhg_dependents); + } + + return 0; +} + + +bool if_nhg_dependents_is_empty(const struct interface *ifp) +{ + if (ifp->info) { + struct zebra_if *zif = (struct zebra_if *)ifp->info; + + return nhg_connected_head_is_empty(&zif->nhg_dependents); + } + + return false; } -/** - * nhe_connected_free() - Free nhe_connected structure - * - * @nhe_connected: nhe_connected structure to free - */ -void nhe_connected_free(struct nhe_connected *connected) { - XFREE(MTYPE_NHE_CONNECTED, connected); } /* Interface is up. */ @@ -1183,16 +1193,9 @@ static void nbr_connected_dump_vty(struct vty *vty, vty_out(vty, "\n"); } -/** - * nhe_connected_dump() - Dump nexthops connected to this interface to vty - * - * @vty: Vty output - * @nhe_connected: List of connected nexthop hash entries - */ -static void nhe_connected_dump_vty(struct vty *vty, - struct nhe_connected *connected) +static void nhg_dependent_dump_vty(struct vty *vty, + struct nhg_connected *connected) { - /* Just outputing ID for now. */ vty_out(vty, " (%u)", connected->nhe->id); } @@ -1343,7 +1346,6 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) { struct connected *connected; struct nbr_connected *nbr_connected; - struct nhe_connected *nhe_connected; struct listnode *node; struct route_node *rn; struct zebra_if *zebra_if; @@ -1429,11 +1431,14 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) connected_dump_vty(vty, connected); } - if (listhead(zebra_if->nhe_connected)) { + if (!if_nhg_dependents_is_empty(ifp)) { + struct nhg_connected *rb_node_dep = NULL; + vty_out(vty, " Nexthop IDs connected:"); - for (ALL_LIST_ELEMENTS_RO(zebra_if->nhe_connected, node, - nhe_connected)) - nhe_connected_dump_vty(vty, nhe_connected); + RB_FOREACH (rb_node_dep, nhg_connected_head, + &zebra_if->nhg_dependents) { + nhg_dependent_dump_vty(vty, rb_node_dep); + } vty_out(vty, "\n"); } diff --git a/zebra/interface.h b/zebra/interface.h index 7dccaeaccb..d5c1e17131 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -264,12 +264,6 @@ typedef enum { struct irdp_interface; -/* Nexthop hash entry connected structure */ -struct nhe_connected { - /* Connected nexthop hash entry */ - struct nhg_hash_entry *nhe; -}; - /* `zebra' daemon local interface structure. */ struct zebra_if { /* Shutdown configuration. */ @@ -284,14 +278,14 @@ struct zebra_if { /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; - /* Nexthops pointed to it list */ + /* Nexthops pointing to this interface */ /** * Any nexthop that we get should have an * interface. When an interface goes down, * we will use this list to update the nexthops * pointing to it with that info. */ - struct list *nhe_connected; + struct nhg_connected_head nhg_dependents; /* Information about up/down changes */ unsigned int up_count; @@ -440,11 +434,13 @@ extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, extern void zebra_if_update_all_links(void); extern void zebra_if_set_protodown(struct interface *ifp, bool down); -/* Nexthop connected list functions */ -struct nhe_connected *nhe_connected_add(struct interface *ifp, - struct nhg_hash_entry *nhe); -struct nhe_connected *nhe_connected_new(void); -void nhe_connected_free(struct nhe_connected *connected); +/* Nexthop group connected functions */ +extern void if_nhg_dependents_add(struct interface *ifp, + struct nhg_hash_entry *nhe); +extern void if_nhg_dependents_del(struct interface *ifp, + struct nhg_hash_entry *nhe); +extern unsigned int if_nhg_dependents_count(const struct interface *ifp); +extern bool if_nhg_dependents_is_empty(const struct interface *ifp); extern void vrf_add_update(struct vrf *vrfp); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index bdf613cef4..d2d9060b84 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -763,6 +763,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, XFREE(MTYPE_RE, re); } } else { + // TODO: Use nhe_id here as well if (!tb[RTA_MULTIPATH]) { struct nexthop nh; size_t sz = (afi == AFI_IP) ? 4 : 16; @@ -2251,7 +2252,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, zlog_debug("Nexthop group type: %d", *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); - zebra_nhg_connected_head_init(nhg_depends); + nhg_connected_head_init(nhg_depends); for (int i = 0; i < count; i++) { /* We do not care about nexthop_grp.weight at @@ -2261,7 +2262,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, */ depend = zebra_nhg_lookup_id(n_grp[i].id); if (depend) { - zebra_nhg_connected_head_add(nhg_depends, depend); + nhg_connected_head_add(nhg_depends, depend); /* * If this is a nexthop with its own group * dependencies, add them as well. Not sure its @@ -2411,14 +2412,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* This is a change to a group we already have */ - // TODO: Fix this for routes referencing it - /* Free what's already there */ - zebra_nhg_free_members(nhe); - - /* Update with new info */ - nhe->nhg = nhg; - if (dep_count) - nhe->nhg_depends = nhg_depends; + zebra_nhg_set_invalid(nhe); + zebra_nhg_free_group_depends(&nhg, &nhg_depends); } else { /* This is a new nexthop group */ @@ -2435,6 +2430,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } nhe->is_kernel_nh = true; + if (id != nhe->id) { /* Duplicate but with different ID from * the kernel */ @@ -2449,18 +2445,18 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) EC_ZEBRA_DUPLICATE_NHG_MESSAGE, "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring", id); - zebra_nhg_connected_head_free(&nhg_depends); + nhg_connected_head_free(&nhg_depends); + } else { + /* Add the nhe to the interface's tree + * of connected nhe's + */ + if (ifp) + zebra_nhg_set_if(nhe, ifp); + + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); } } - if (ifp) { - /* Add the nhe to the interface's list - * of connected nhe's - */ - // TODO: Don't add dupes - nhe_connected_add(ifp, nhe); - } - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); } else if (h->nlmsg_type == RTM_DELNEXTHOP) { if (!nhe) { @@ -2471,9 +2467,10 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_set_invalid(nhe); - // TODO: Run some active check on all route_entry's? + // TODO: Probably won't need this if we expect + // upper level protocol to fix it. if (nhe->refcnt) { flog_err( EC_ZEBRA_NHG_SYNC, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index d3204bdf48..44265bc580 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -40,22 +40,22 @@ #include "zebra/rt.h" #include "zebra_errors.h" #include "zebra_dplane.h" +#include "zebra/interface.h" DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected"); -static int zebra_nhg_connected_cmp(const struct nhg_connected *dep1, - const struct nhg_connected *dep2); +static int nhg_connected_cmp(const struct nhg_connected *dep1, + const struct nhg_connected *dep2); -RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, - zebra_nhg_connected_cmp); +RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); -static void nhg_connected_free(struct nhg_connected *dep) +void nhg_connected_free(struct nhg_connected *dep) { XFREE(MTYPE_NHG_CONNECTED, dep); } -static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) +struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) { struct nhg_connected *new = NULL; @@ -65,35 +65,42 @@ static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) return new; } -static uint8_t zebra_nhg_connected_count(const struct nhg_connected_head *head) +void nhg_connected_head_init(struct nhg_connected_head *head) +{ + RB_INIT(nhg_connected_head, head); +} + +void nhg_connected_head_free(struct nhg_connected_head *head) { struct nhg_connected *rb_node_dep = NULL; - uint8_t i = 0; + struct nhg_connected *tmp = NULL; - RB_FOREACH (rb_node_dep, nhg_connected_head, head) { - i++; + if (!nhg_connected_head_is_empty(head)) { + RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) { + RB_REMOVE(nhg_connected_head, head, rb_node_dep); + nhg_connected_free(rb_node_dep); + } } - return i; } -uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) +unsigned int nhg_connected_head_count(const struct nhg_connected_head *head) { - return zebra_nhg_connected_count(&nhe->nhg_depends); -} + struct nhg_connected *rb_node_dep = NULL; + unsigned int i = 0; -static bool -zebra_nhg_connected_head_is_empty(const struct nhg_connected_head *head) -{ - return RB_EMPTY(nhg_connected_head, head); + RB_FOREACH (rb_node_dep, nhg_connected_head, head) { + i++; + } + return i; } -bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) +bool nhg_connected_head_is_empty(const struct nhg_connected_head *head) { - return zebra_nhg_connected_head_is_empty(&nhe->nhg_depends); + return RB_EMPTY(nhg_connected_head, head); } -void zebra_nhg_connected_head_del(struct nhg_connected_head *head, - struct nhg_hash_entry *depend) +void nhg_connected_head_del(struct nhg_connected_head *head, + struct nhg_hash_entry *depend) { struct nhg_connected lookup = {}; struct nhg_connected *removed = NULL; @@ -105,8 +112,8 @@ void zebra_nhg_connected_head_del(struct nhg_connected_head *head, nhg_connected_free(removed); } -void zebra_nhg_connected_head_add(struct nhg_connected_head *head, - struct nhg_hash_entry *depend) +void nhg_connected_head_add(struct nhg_connected_head *head, + struct nhg_hash_entry *depend) { struct nhg_connected *new = NULL; @@ -115,28 +122,14 @@ void zebra_nhg_connected_head_add(struct nhg_connected_head *head, RB_INSERT(nhg_connected_head, head, new); } -/** - * zebra_nhg_dependents_del() - Delete a dependent from the nhg_hash_entry - * - * @from: Nexthop group hash entry we are deleting from - * @dependent: Dependent we are deleting - */ -void zebra_nhg_dependents_del(struct nhg_hash_entry *from, - struct nhg_hash_entry *dependent) +unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) { - zebra_nhg_connected_head_del(&from->nhg_dependents, dependent); + return nhg_connected_head_count(&nhe->nhg_depends); } -/** - * zebra_nhg_dependents_add() - Add a new dependent to the nhg_hash_entry - * - * @to: Nexthop group hash entry we are adding to - * @dependent: Dependent we are adding - */ -void zebra_nhg_dependents_add(struct nhg_hash_entry *to, - struct nhg_hash_entry *dependent) +bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) { - zebra_nhg_connected_head_add(&to->nhg_dependents, dependent); + return nhg_connected_head_is_empty(&nhe->nhg_depends); } /** @@ -148,7 +141,7 @@ void zebra_nhg_dependents_add(struct nhg_hash_entry *to, void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend) { - zebra_nhg_connected_head_del(&from->nhg_depends, depend); + nhg_connected_head_del(&from->nhg_depends, depend); /* Delete from the dependent tree */ zebra_nhg_dependents_del(depend, from); @@ -163,12 +156,7 @@ void zebra_nhg_depends_del(struct nhg_hash_entry *from, void zebra_nhg_depends_add(struct nhg_hash_entry *to, struct nhg_hash_entry *depend) { - zebra_nhg_connected_head_add(&to->nhg_depends, depend); -} - -void zebra_nhg_connected_head_init(struct nhg_connected_head *head) -{ - RB_INIT(nhg_connected_head, head); + nhg_connected_head_add(&to->nhg_depends, depend); } /** @@ -178,10 +166,9 @@ void zebra_nhg_connected_head_init(struct nhg_connected_head *head) */ void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) { - zebra_nhg_connected_head_init(&nhe->nhg_depends); + nhg_connected_head_init(&nhe->nhg_depends); } - /** * zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal * @@ -217,6 +204,50 @@ static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1, return true; } +unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe) +{ + return nhg_connected_head_count(&nhe->nhg_dependents); +} + +bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe) +{ + return nhg_connected_head_is_empty(&nhe->nhg_dependents); +} + +/** + * zebra_nhg_dependents_del() - Delete a dependent from the nhg_hash_entry + * + * @from: Nexthop group hash entry we are deleting from + * @dependent: Dependent we are deleting + */ +void zebra_nhg_dependents_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *dependent) +{ + nhg_connected_head_del(&from->nhg_dependents, dependent); +} + +/** + * zebra_nhg_dependents_add() - Add a new dependent to the nhg_hash_entry + * + * @to: Nexthop group hash entry we are adding to + * @dependent: Dependent we are adding + */ +void zebra_nhg_dependents_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *dependent) +{ + nhg_connected_head_add(&to->nhg_dependents, dependent); +} + +/** + * zebra_nhg_dependents_init() - Initialize tree for nhg dependents + * + * @nhe: Nexthop group hash entry + */ +void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe) +{ + nhg_connected_head_init(&nhe->nhg_dependents); +} + /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table * @@ -280,6 +311,7 @@ static void *zebra_nhg_alloc(void *arg) nhe->ifp = NULL; /* Attach backpointer to anything that it depends on */ + zebra_nhg_dependents_init(nhe); if (!zebra_nhg_depends_is_empty(nhe)) { RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe->nhg_depends) { @@ -291,6 +323,10 @@ static void *zebra_nhg_alloc(void *arg) zebra_nhg_insert_id(nhe); + // TODO: This needs to be moved + // It should only install AFTER it gets + // the ifp right? + // /* Send it to the kernel */ if (!nhe->is_kernel_nh) zebra_nhg_install_kernel(nhe); @@ -362,8 +398,8 @@ static int zebra_nhg_cmp(const struct nhg_hash_entry *nhe1, return nhe1->id - nhe2->id; } -static int zebra_nhg_connected_cmp(const struct nhg_connected *dep1, - const struct nhg_connected *dep2) +static int nhg_connected_cmp(const struct nhg_connected *dep1, + const struct nhg_connected *dep2) { return zebra_nhg_cmp(dep1->nhe, dep2->nhe); } @@ -475,19 +511,6 @@ struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi) return nhe; } -void zebra_nhg_connected_head_free(struct nhg_connected_head *head) -{ - struct nhg_connected *rb_node_dep = NULL; - struct nhg_connected *tmp = NULL; - - if (!zebra_nhg_connected_head_is_empty(head)) { - RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) { - RB_REMOVE(nhg_connected_head, head, rb_node_dep); - nhg_connected_free(rb_node_dep); - } - } -} - /** * zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group * struct and depends @@ -508,7 +531,7 @@ void zebra_nhg_free_group_depends(struct nexthop_group **nhg, // // if (head) - zebra_nhg_connected_head_free(head); + nhg_connected_head_free(head); if (nhg) nexthop_group_free_delete(nhg); @@ -526,7 +549,7 @@ void zebra_nhg_free_members(struct nhg_hash_entry *nhe) zebra_nhg_free_group_depends(&nhe->nhg, &nhe->nhg_depends); // TODO: Fixup this function - zebra_nhg_connected_head_free(&nhe->nhg_dependents); + nhg_connected_head_free(&nhe->nhg_dependents); } /** @@ -560,17 +583,6 @@ void zebra_nhg_release(struct nhg_hash_entry *nhe) } } -/** - * zebra_nhg_uninstall_release() - Unistall and release a nhe - * - * @nhe: Nexthop group hash entry - */ -static void zebra_nhg_uninstall_release(struct nhg_hash_entry *nhe) -{ - zebra_nhg_uninstall_kernel(nhe); - // zebra_nhg_release(nhe); -} - /** * zebra_nhg_decrement_ref() - Decrement the reference count, release if unused * @@ -616,6 +628,29 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) nhe->refcnt++; } +void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) +{ + + if (!zebra_nhg_dependents_is_empty(nhe)) { + struct nhg_connected *rb_node_dep = NULL; + + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_dependents) { + zebra_nhg_set_invalid(rb_node_dep->nhe); + } + } + + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + /* Assuming uninstalled as well here */ + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); +} + +void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) +{ + nhe->ifp = ifp; + if_nhg_dependents_add(ifp, nhe); +} + static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, struct nexthop *nexthop) { diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 4aa59e7530..ebdc3a636f 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -96,30 +96,46 @@ struct nhg_connected { struct nhg_hash_entry *nhe; }; -RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, - zebra_nhg_connected_cmp); +RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); void zebra_nhg_init(void); void zebra_nhg_terminate(void); -extern uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); +extern void nhg_connected_free(struct nhg_connected *dep); +extern struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe); + +/* nhg connected tree direct access functions */ +extern void nhg_connected_head_init(struct nhg_connected_head *head); +extern unsigned int +nhg_connected_head_count(const struct nhg_connected_head *head); +extern void nhg_connected_head_free(struct nhg_connected_head *head); +extern bool nhg_connected_head_is_empty(const struct nhg_connected_head *head); +extern void nhg_connected_head_del(struct nhg_connected_head *head, + struct nhg_hash_entry *nhe); +extern void nhg_connected_head_add(struct nhg_connected_head *head, + struct nhg_hash_entry *nhe); + +/** + * NHE abstracted tree functions. + * Use these where possible instead of the direct ones access ones. + */ +/* Depends */ +extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe); -extern void zebra_nhg_connected_head_del(struct nhg_connected_head *head, - struct nhg_hash_entry *nhe); -extern void zebra_nhg_connected_head_add(struct nhg_connected_head *head, - struct nhg_hash_entry *nhe); -extern void zebra_nhg_dependents_del(struct nhg_hash_entry *from, - struct nhg_hash_entry *dependent); -extern void zebra_nhg_dependents_add(struct nhg_hash_entry *to, - struct nhg_hash_entry *dependent); extern void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend); extern void zebra_nhg_depends_add(struct nhg_hash_entry *to, struct nhg_hash_entry *depend); -extern void zebra_nhg_connected_head_init(struct nhg_connected_head *head); extern void zebra_nhg_depends_init(struct nhg_hash_entry *nhe); -extern void zebra_nhg_depends_copy(struct nhg_hash_entry *to, - struct nhg_hash_entry *from); +/* Dependents */ +extern unsigned int +zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe); +extern bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe); +extern void zebra_nhg_dependents_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *dependent); +extern void zebra_nhg_dependents_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *dependent); +extern void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe); extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id); @@ -140,7 +156,6 @@ extern struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi); -void zebra_nhg_connected_head_free(struct nhg_connected_head *head); void zebra_nhg_free_group_depends(struct nexthop_group **nhg, struct nhg_connected_head *head); void zebra_nhg_free_members(struct nhg_hash_entry *nhe); @@ -148,6 +163,8 @@ void zebra_nhg_free(void *arg); void zebra_nhg_release(struct nhg_hash_entry *nhe); void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); +void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe); +void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp); extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7015ff77de..898076b017 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2667,7 +2667,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct nexthop lookup = {0}; struct nhg_hash_entry *depend = NULL; - zebra_nhg_connected_head_init(&nhg_depends); + nhg_connected_head_init(&nhg_depends); for (ALL_NEXTHOPS_PTR(re->ng, nh)) { lookup = *nh; @@ -2675,7 +2675,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, lookup.next = NULL; /* Use the route afi here, since a single nh */ depend = zebra_nhg_find_nexthop(&lookup, afi); - zebra_nhg_connected_head_add(&nhg_depends, depend); + nhg_connected_head_add(&nhg_depends, depend); } /* change the afi for group */ @@ -2698,7 +2698,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, EC_ZEBRA_TABLE_LOOKUP_FAILED, "Zebra failed to find or create a nexthop hash entry for id=%u in a route entry", re->nhe_id); - zebra_nhg_connected_head_free(&nhg_depends); + nhg_connected_head_free(&nhg_depends); } -- cgit v1.2.3 From bbb3940ed11d62df8263bb97ef393c1d7de0220b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 12:00:51 -0400 Subject: zebra: VRF ID should be null if a nexthop group A nexthop group should not have a VRF ID. Only individual nexthops need to be using a VRF. Fixed this both kernel and proto side. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 2 +- zebra/zebra_rib.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index d2d9060b84..db8e28cea0 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2298,7 +2298,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) uint32_t id; unsigned char family; afi_t afi = AFI_UNSPEC; - vrf_id_t vrf_id = VRF_DEFAULT; + vrf_id_t vrf_id = 0; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; /* struct for nexthop group abstraction */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 898076b017..96e5816da3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2641,6 +2641,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct nhg_connected_head nhg_depends = {0}; /* Default to route afi */ afi_t nhg_afi = afi; + /* Default to route vrf id */ + vrf_id_t nhg_vrf_id = re->vrf_id; int ret = 0; if (!re) @@ -2680,10 +2682,11 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* change the afi for group */ nhg_afi = AFI_UNSPEC; + nhg_vrf_id = 0; } // TODO: Add proto type here - nhe = zebra_nhg_find(re->ng, re->vrf_id, nhg_afi, re->nhe_id, + nhe = zebra_nhg_find(re->ng, nhg_vrf_id, nhg_afi, re->nhe_id, &nhg_depends, false); if (nhe) { -- cgit v1.2.3 From 13dfea50e4aba145d57ce32247208d7108d5e803 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Apr 2019 19:15:43 -0400 Subject: zebra: Check for nexthop group before free on fail Check to make sure the route entry has a nexthop group before we try to free after a table lookup failure. Signed-off-by: Stephen Worley --- zebra/zebra_rib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 96e5816da3..6fe87697b2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2653,7 +2653,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { - nexthop_group_free_delete(&re->ng); + if (re->ng) + nexthop_group_free_delete(&re->ng); XFREE(MTYPE_RE, re); return 0; } -- cgit v1.2.3 From e22e80010ee4226cbb4c1cb570d520ff071add89 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:03:29 -0700 Subject: zebra: Use a nhe context dataplane and rib metaq We will use a nhe context for dataplane interaction with nextho group hash entries. New nhe's from the kernel will be put into a group array if they are a group and queued on the rib metaq to be processed later. New nhe's sent to the kernel will be set on the dataplane context with approprate ID's in the group array if needed. Signed-off-by: Stephen Worley --- lib/route_types.txt | 2 + zebra/interface.c | 17 +- zebra/interface.h | 1 - zebra/rib.h | 23 ++- zebra/rt_netlink.c | 212 +++++++----------------- zebra/zebra_dplane.c | 25 +-- zebra/zebra_dplane.h | 6 +- zebra/zebra_nhg.c | 454 ++++++++++++++++++++++++++++++++++++++++----------- zebra/zebra_nhg.h | 68 +++++++- zebra/zebra_rib.c | 263 ++++++++++++++++------------- 10 files changed, 677 insertions(+), 394 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/lib/route_types.txt b/lib/route_types.txt index 59f3a91cf0..71d0a46449 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -84,6 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR" ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD" ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric" ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP" +ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group" ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-" @@ -113,3 +114,4 @@ ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)" ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)" ZEBRA_ROUTE_VRRP, "Virtual Router Redundancy Protocol (VRRP)" ZEBRA_ROUTE_OPENFABRIC, "OpenFabric Routing Protocol" +ZEBRA_ROUTE_NHG, "Zebra Nexthop Groups (NHG)" diff --git a/zebra/interface.c b/zebra/interface.c index 798cb92690..94f5cb58cd 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -189,6 +189,20 @@ static int if_zebra_new_hook(struct interface *ifp) return 0; } +static void if_nhg_dependents_release(struct interface *ifp) +{ + if (!if_nhg_dependents_is_empty(ifp)) { + struct nhg_connected *rb_node_dep = NULL; + struct zebra_if *zif = (struct zebra_if *)ifp->info; + + RB_FOREACH (rb_node_dep, nhg_connected_head, + &zif->nhg_dependents) { + rb_node_dep->nhe->ifp = NULL; + zebra_nhg_set_invalid(rb_node_dep->nhe); + } + } +} + /* Called when interface is deleted. */ static int if_zebra_delete_hook(struct interface *ifp) { @@ -210,6 +224,7 @@ static int if_zebra_delete_hook(struct interface *ifp) list_delete(&rtadv->AdvDNSSLList); #endif /* HAVE_RTADV */ + if_nhg_dependents_release(ifp); zebra_if_nhg_dependents_free(zebra_if); XFREE(MTYPE_TMP, zebra_if->desc); @@ -983,7 +998,7 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp) return false; } -void if_down_nhg_dependents(const struct interface *ifp) +static void if_down_nhg_dependents(const struct interface *ifp) { if (!if_nhg_dependents_is_empty(ifp)) { struct nhg_connected *rb_node_dep = NULL; diff --git a/zebra/interface.h b/zebra/interface.h index c5614a2a60..d5c1e17131 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -441,7 +441,6 @@ extern void if_nhg_dependents_del(struct interface *ifp, struct nhg_hash_entry *nhe); extern unsigned int if_nhg_dependents_count(const struct interface *ifp); extern bool if_nhg_dependents_is_empty(const struct interface *ifp); -extern void if_down_nhg_dependents(const struct interface *ifp); extern void vrf_add_update(struct vrf *vrfp); diff --git a/zebra/rib.h b/zebra/rib.h index 6b8097dd13..2652b12abf 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -153,13 +153,14 @@ struct route_entry { #define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type) /* meta-queue structure: - * sub-queue 0: connected, kernel - * sub-queue 1: static - * sub-queue 2: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP - * sub-queue 3: iBGP, eBGP - * sub-queue 4: any other origin (if any) + * sub-queue 0: nexthop group objects + * sub-queue 1: connected, kernel + * sub-queue 2: static + * sub-queue 3: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP + * sub-queue 4: iBGP, eBGP + * sub-queue 5: any other origin (if any) */ -#define MQ_SIZE 5 +#define MQ_SIZE 6 struct meta_queue { struct list *subq[MQ_SIZE]; uint32_t size; /* sum of lengths of all subqueues */ @@ -209,7 +210,7 @@ DECLARE_LIST(re_list, struct route_entry, next); #define RIB_ROUTE_QUEUED(x) (1 << (x)) // If MQ_SIZE is modified this value needs to be updated. -#define RIB_ROUTE_ANY_QUEUED 0x1F +#define RIB_ROUTE_ANY_QUEUED 0x3F /* * The maximum qindex that can be used. @@ -397,7 +398,13 @@ extern unsigned long rib_score_proto(uint8_t proto, unsigned short instance); extern unsigned long rib_score_proto_table(uint8_t proto, unsigned short instance, struct route_table *table); -extern void rib_queue_add(struct route_node *rn); + +extern int rib_queue_add(struct route_node *rn); + +struct nhg_ctx; /* Forward declaration */ + +extern int rib_queue_nhg_add(struct nhg_ctx *ctx); + extern void meta_queue_free(struct meta_queue *mq); extern int zebra_rib_labeled_unicast(struct route_entry *re); extern struct route_table *rib_table_ipv6; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ae0cf8ab45..419e8ffb6e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1889,11 +1889,11 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) * * @n: Netlink message header struct * @req_size: Size allocated for this message - * @depends_info: Array of depend_info structs + * @z_grp: Array of nh_grp structs * @count: How many depencies there are */ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, - const struct depend_info *depends_info, + const struct nh_grp *z_grp, const uint8_t count) { struct nexthop_grp grp[count]; @@ -1902,8 +1902,8 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, if (count) { for (int i = 0; i < count; i++) { - grp[i].id = depends_info[i].id; - grp[i].weight = depends_info[i].weight; + grp[i].id = z_grp[i].id; + grp[i].weight = z_grp[i].weight; } addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp)); } @@ -1946,11 +1946,11 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) addattr32(&req.n, sizeof(req), NHA_ID, id); if (cmd == RTM_NEWNEXTHOP) { - if (dplane_ctx_get_nhe_depends_count(ctx)) + if (dplane_ctx_get_nhe_nh_grp_count(ctx)) _netlink_nexthop_build_group( &req.n, sizeof(req), - dplane_ctx_get_nhe_depends_info(ctx), - dplane_ctx_get_nhe_depends_count(ctx)); + dplane_ctx_get_nhe_nh_grp(ctx), + dplane_ctx_get_nhe_nh_grp_count(ctx)); else { const struct nexthop *nh = dplane_ctx_get_nhe_ng(ctx)->nexthop; @@ -2144,16 +2144,16 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * * Return: New nexthop */ -static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb, - unsigned char family, - struct interface **ifp, - ns_id_t ns_id) +static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, + unsigned char family, + struct interface **ifp, + ns_id_t ns_id) { - struct nexthop *nh = NULL; + struct nexthop nh = {}; void *gate = NULL; enum nexthop_types_t type = 0; - int if_index; - size_t sz; + int if_index = 0; + size_t sz = 0; if_index = *(int *)RTA_DATA(tb[NHA_OIF]); @@ -2173,35 +2173,31 @@ static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb, EC_ZEBRA_BAD_NHG_MESSAGE, "Nexthop gateway with bad address family (%d) received from kernel", family); - return NULL; + return nh; } gate = RTA_DATA(tb[NHA_GATEWAY]); - } else { + } else type = NEXTHOP_TYPE_IFINDEX; - } - - /* Allocate the new nexthop */ - nh = nexthop_new(); if (type) - nh->type = type; + nh.type = type; if (gate) - memcpy(&(nh->gate), gate, sz); + memcpy(&(nh.gate), gate, sz); if (if_index) - nh->ifindex = if_index; + nh.ifindex = if_index; - *ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh->ifindex); - if (ifp) { - nh->vrf_id = (*ifp)->vrf_id; - } else { + *ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex); + if (ifp) + nh.vrf_id = (*ifp)->vrf_id; + else { flog_warn( EC_ZEBRA_UNKNOWN_INTERFACE, "%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT", - __PRETTY_FUNCTION__, nh->ifindex); + __PRETTY_FUNCTION__, nh.ifindex); - nh->vrf_id = VRF_DEFAULT; + nh.vrf_id = VRF_DEFAULT; } if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) { @@ -2209,35 +2205,23 @@ static struct nexthop *netlink_nexthop_process_nh(struct rtattr **tb, int num_labels = 0; mpls_label_t labels[MPLS_MAX_LABELS] = {0}; - if (encap_type == LWTUNNEL_ENCAP_MPLS) { + if (encap_type == LWTUNNEL_ENCAP_MPLS) num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels); - } - if (num_labels) { - nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, + if (num_labels) + nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); - } } return nh; } -/** - * netlink_nexthop_process_group() - Iterate over nhmsg nexthop group - * - * @tb: Netlink RTA data - * @nhg_depends: Tree head of nexthops in the group - * @nhg: Nexthop group struct - * - * Return: Count of nexthops in the group - */ static int netlink_nexthop_process_group(struct rtattr **tb, - struct nexthop_group *nhg, - struct nhg_connected_head *nhg_depends) + struct nh_grp *z_grp) { - int count = 0; + uint8_t count = 0; + /* linux/nexthop.h group struct */ struct nexthop_grp *n_grp = NULL; - struct nhg_hash_entry *depend = NULL; n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]); count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp)); @@ -2252,32 +2236,10 @@ static int netlink_nexthop_process_group(struct rtattr **tb, zlog_debug("Nexthop group type: %d", *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); - nhg_connected_head_init(nhg_depends); for (int i = 0; i < count; i++) { - /* We do not care about nexthop_grp.weight at - * this time. But we should figure out - * how to adapt this to our code in - * the future. - */ - depend = zebra_nhg_lookup_id(n_grp[i].id); - if (depend) { - nhg_connected_head_add(nhg_depends, depend); - /* - * If this is a nexthop with its own group - * dependencies, add them as well. Not sure its - * even possible to have a group within a group - * in the kernel. - */ - - copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, - NULL); - } else { - flog_err( - EC_ZEBRA_NHG_SYNC, - "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table", - n_grp[i].id); - } + z_grp[i].id = n_grp[i].id; + z_grp[i].weight = n_grp[i].weight; } return count; } @@ -2301,16 +2263,13 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) vrf_id_t vrf_id = 0; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; - /* struct for nexthop group abstraction */ - struct nexthop_group *nhg = NULL; - struct nexthop *nh = NULL; - /* If its a group, tree head of nexthops */ - struct nhg_connected_head nhg_depends = {0}; + struct nexthop nh = {}; + struct nh_grp grp[MULTIPATH_NUM] = {}; /* Count of nexthops in group array */ - int dep_count = 0; + uint8_t grp_count = 0; /* struct that goes into our tables */ struct nhg_hash_entry *nhe = NULL; - struct rtattr *tb[NHA_MAX + 1]; + struct rtattr *tb[NHA_MAX + 1] = {}; nhm = NLMSG_DATA(h); @@ -2327,7 +2286,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } - memset(tb, 0, sizeof(tb)); netlink_parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len); @@ -2351,18 +2309,13 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) nl_family_to_str(family), ns_id); - nhe = zebra_nhg_lookup_id(id); - if (h->nlmsg_type == RTM_NEWNEXTHOP) { - nhg = nexthop_group_new(); - if (tb[NHA_GROUP]) { /** * If this is a group message its only going to have * an array of nexthop IDs associated with it */ - dep_count = netlink_nexthop_process_group(tb, nhg, - &nhg_depends); + grp_count = netlink_nexthop_process_group(tb, grp); } else { if (tb[NHA_BLACKHOLE]) { /** @@ -2370,92 +2323,42 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) * traffic, it should not have an OIF, GATEWAY, * or ENCAP */ - nh = nexthop_new(); - nh->type = NEXTHOP_TYPE_BLACKHOLE; - nh->bh_type = BLACKHOLE_UNSPEC; - } else if (tb[NHA_OIF]) { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = BLACKHOLE_UNSPEC; + } else if (tb[NHA_OIF]) /** * This is a true new nexthop, so we need * to parse the gateway and device info */ nh = netlink_nexthop_process_nh(tb, family, &ifp, ns_id); - } - if (nh) { - SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE); - if (nhm->nh_flags & RTNH_F_ONLINK) - SET_FLAG(nh->flags, - NEXTHOP_FLAG_ONLINK); - vrf_id = nh->vrf_id; - nexthop_group_add_sorted(nhg, nh); - } else { + else { + flog_warn( EC_ZEBRA_BAD_NHG_MESSAGE, "Invalid Nexthop message received from the kernel with ID (%u)", id); return -1; } + SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE); + if (nhm->nh_flags & RTNH_F_ONLINK) + SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); + vrf_id = nh.vrf_id; } - if (!nhg->nexthop) { - /* Nothing to lookup */ - nexthop_group_free_delete(&nhg); - nhg_connected_head_free(&nhg_depends); - return -1; - } - - if (nhe) { - // TODO: Apparently we don't want changes - // to already created one in our table. - // They should be immutable... - // Gotta figure that one out. - - /* This is a change to a group we already have - */ - - zebra_nhg_set_invalid(nhe); - nexthop_group_free_delete(&nhg); - nhg_connected_head_free(&nhg_depends); + // TODO: Apparently we don't want changes + // to already created one in our table. + // They should be immutable... + // Gotta figure that one out. - } else { - /* This is a new nexthop group */ - nhe = zebra_nhg_find(nhg, vrf_id, afi, id, &nhg_depends, - true); - /* The group was copied over, so free it */ - nexthop_group_free_delete(&nhg); - - if (!nhe) { - flog_err( - EC_ZEBRA_TABLE_LOOKUP_FAILED, - "Zebra failed to find or create a nexthop hash entry for ID (%u) from the kernel", - id); - return -1; - } - nhe->is_kernel_nh = true; - - if (id != nhe->id) { - /* Duplicate but with different ID from - * the kernel */ + if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi)) + return -1; - /* The kernel allows duplicate nexthops - * as long as they have different IDs. - * We are ignoring those to prevent - * syncing problems with the kernel - * changes. - */ - flog_warn( - EC_ZEBRA_DUPLICATE_NHG_MESSAGE, - "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring", - id); - nhg_connected_head_free(&nhg_depends); - } else { - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - } - } } else if (h->nlmsg_type == RTM_DELNEXTHOP) { + // TODO: Add new function in nhgc to handle del + nhe = zebra_nhg_lookup_id(id); if (!nhe) { flog_warn( EC_ZEBRA_BAD_NHG_MESSAGE, @@ -2474,9 +2377,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Kernel deleted a nexthop group with ID (%u) that we are still using for a route, sending it back down", nhe->id); zebra_nhg_install_kernel(nhe); - } else { - zebra_nhg_release(nhe); - } + } else + zebra_nhg_set_invalid(nhe); } return 0; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e4890319d9..21427b8063 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -76,8 +76,8 @@ struct dplane_nexthop_info { bool is_kernel_nh; struct nexthop_group ng; - struct depend_info depends_info[MULTIPATH_NUM]; - uint8_t depends_count; + struct nh_grp nh_grp[MULTIPATH_NUM]; + uint8_t nh_grp_count; }; /* @@ -1090,17 +1090,17 @@ dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx) return &(ctx->u.rinfo.nhe.ng); } -const struct depend_info * -dplane_ctx_get_nhe_depends_info(const struct zebra_dplane_ctx *ctx) +const struct nh_grp * +dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rinfo.nhe.depends_info; + return ctx->u.rinfo.nhe.nh_grp; } -uint8_t dplane_ctx_get_nhe_depends_count(const struct zebra_dplane_ctx *ctx) +uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rinfo.nhe.depends_count; + return ctx->u.rinfo.nhe.nh_grp_count; } /* Accessors for LSP information */ @@ -1572,15 +1572,18 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, struct nhg_connected *rb_node_dep = NULL; uint8_t i = 0; + // TODO: This doesn't work with depends being recursive + // resolved nh's as well. Yea, good luck future stephen + // this one... + RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe->nhg_depends) { - ctx->u.rinfo.nhe.depends_info[i].id = - rb_node_dep->nhe->id; + ctx->u.rinfo.nhe.nh_grp[i].id = rb_node_dep->nhe->id; /* We aren't using weights for anything right now */ - ctx->u.rinfo.nhe.depends_info[i].weight = 0; + ctx->u.rinfo.nhe.nh_grp[i].weight = 0; i++; } - ctx->u.rinfo.nhe.depends_count = i; + ctx->u.rinfo.nhe.nh_grp_count = i; } /* Extract ns info - can't use pointers to 'core' diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 447e9c0d7f..d0fde958e4 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -282,9 +282,9 @@ vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx); bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx); const struct nexthop_group * dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx); -const struct depend_info * -dplane_ctx_get_nhe_depends_info(const struct zebra_dplane_ctx *ctx); -uint8_t dplane_ctx_get_nhe_depends_count(const struct zebra_dplane_ctx *ctx); +const struct nh_grp * +dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx); +uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); /* Accessors for LSP information */ mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 7373805d2c..67f72d1e82 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -44,12 +44,14 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected"); +DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context"); static int nhg_connected_cmp(const struct nhg_connected *dep1, const struct nhg_connected *dep2); RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); + void nhg_connected_free(struct nhg_connected *dep) { XFREE(MTYPE_NHG_CONNECTED, dep); @@ -286,12 +288,9 @@ static void *zebra_nhg_alloc(void *arg) struct nhg_hash_entry *copy = arg; struct nhg_connected *rb_node_dep = NULL; - nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry)); - nhe->id = copy->id; - nhe->nhg_depends = copy->nhg_depends; nhe->nhg = nexthop_group_new(); @@ -334,15 +333,6 @@ static void *zebra_nhg_alloc(void *arg) /* Add to id table as well */ zebra_nhg_insert_id(nhe); - - // TODO: This needs to be moved - // It should only install AFTER it gets - // the ifp right? - // - /* Send it to the kernel */ - if (!nhe->is_kernel_nh) - zebra_nhg_install_kernel(nhe); - return nhe; } @@ -410,72 +400,70 @@ static int nhg_connected_cmp(const struct nhg_connected *con1, return (con1->nhe->id - con2->nhe->id); } -/** - * zebra_nhg_find() - Find the zebra nhg in our table, or create it - * - * @nhg: Nexthop group we lookup with - * @vrf_id: VRF id - * @afi: Address Family type - * @id: ID we lookup with, 0 means its from us and we - * need to give it an ID, otherwise its from the - * kernel as we use the ID it gave us. - * @nhg_depends: Nexthop dependency tree head - * @is_kernel_nh: Was the nexthop created by the kernel - * - * Return: Hash entry found or created - * - * The nhg and n_grp are fundementally the same thing (a group of nexthops). - * We are just using the nhg representation with routes and the n_grp - * is what the kernel gives us (a list of IDs). Our nhg_hash_entry - * will contain both. - * - * nhg_hash_entry example: - * - * nhe: - * ->nhg: - * .nexthop->nexthop->nexthop - * ->nhg_depends: - * .nhe->nhe->nhe - * - * Routes will use the nhg directly, and any updating of nexthops - * we have to do or flag setting, we use the nhg_depends. - * - */ -struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, - vrf_id_t vrf_id, afi_t afi, uint32_t id, - struct nhg_connected_head *nhg_depends, - bool is_kernel_nh) +static void zebra_nhg_process_grp(struct nexthop_group *nhg, + struct nhg_connected_head *depends, + struct nh_grp *grp, uint8_t count) +{ + nhg_connected_head_init(depends); + + for (int i = 0; i < count; i++) { + struct nhg_hash_entry *depend = NULL; + /* We do not care about nexthop_grp.weight at + * this time. But we should figure out + * how to adapt this to our code in + * the future. + */ + depend = zebra_nhg_lookup_id(grp[i].id); + if (depend) { + nhg_connected_head_add(depends, depend); + /* + * If this is a nexthop with its own group + * dependencies, add them as well. Not sure its + * even possible to have a group within a group + * in the kernel. + */ + + copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, + NULL); + } else { + flog_err( + EC_ZEBRA_NHG_SYNC, + "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table", + grp[i].id); + } + } +} + + +static struct nhg_hash_entry * +zebra_nhg_find(uint32_t id, struct nexthop_group *nhg, + struct nhg_connected_head *nhg_depends, vrf_id_t vrf_id, + afi_t afi, bool is_kernel_nh) { - /* lock for getiing and setting the id */ - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; /* id counter to keep in sync with kernel */ static uint32_t id_counter = 0; struct nhg_hash_entry lookup = {}; struct nhg_hash_entry *nhe = NULL; - uint32_t old_id_counter = 0; - - pthread_mutex_lock(&lock); /* Lock, set the id counter */ - old_id_counter = id_counter; + uint32_t old_id_counter = id_counter; - if (id) { - if (id > id_counter) { - /* Increase our counter so we don't try to create - * an ID that already exists - */ - id_counter = id; - } + if (id > id_counter) { + /* Increase our counter so we don't try to create + * an ID that already exists + */ + id_counter = id; lookup.id = id; - } else { + } else lookup.id = ++id_counter; - } - lookup.vrf_id = vrf_id; lookup.afi = afi; - lookup.nhg = nhg; - lookup.nhg_depends = *nhg_depends; + lookup.vrf_id = vrf_id; lookup.is_kernel_nh = is_kernel_nh; + lookup.nhg = nhg; + + if (nhg_depends) + lookup.nhg_depends = *nhg_depends; if (id) nhe = zebra_nhg_lookup_id(id); @@ -486,33 +474,227 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, if (nhe) id_counter = old_id_counter; - pthread_mutex_unlock(&lock); - if (!nhe) nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); return nhe; } -/** - * zebra_nhg_find_nexthop() - Create a group with a single nexthop, find it in - * our table, or create it - * - * @nh: Nexthop to lookup - * @afi: Address Family type - * - * Return: Hash entry found or created - */ -struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi) +/* Find/create a single nexthop */ +static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id, + struct nexthop *nh, + afi_t afi, + bool is_kernel_nh) { + struct nexthop_group nhg = {}; + + _nexthop_group_add_sorted(&nhg, nh); + + return zebra_nhg_find(id, &nhg, NULL, nh->vrf_id, afi, is_kernel_nh); +} + +static struct nhg_ctx *nhg_ctx_new() +{ + struct nhg_ctx *new = NULL; + + new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx)); + + return new; +} + +static void nhg_ctx_free(struct nhg_ctx *ctx) +{ + XFREE(MTYPE_NHG_CTX, ctx); +} + +static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_result status) +{ + ctx->status = status; +} + +static enum nhg_ctx_result nhg_ctx_get_status(const struct nhg_ctx *ctx) +{ + return ctx->status; +} + +static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op) +{ + ctx->op = op; +} + +static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx) +{ + return ctx->op; +} + +static int nhg_ctx_process_new(struct nhg_ctx *ctx) +{ + struct nexthop_group *nhg = NULL; + struct nhg_connected_head nhg_depends = {}; struct nhg_hash_entry *nhe = NULL; - struct nexthop_group *nhg = nexthop_group_new(); + if (ctx->count) { + nhg = nexthop_group_new(); + zebra_nhg_process_grp(nhg, &nhg_depends, ctx->u.grp, + ctx->count); + nhe = zebra_nhg_find(ctx->id, nhg, &nhg_depends, ctx->vrf_id, + ctx->afi, true); + /* These got copied over in zebra_nhg_alloc() */ + nexthop_group_free_delete(&nhg); + } else + nhe = zebra_nhg_find_nexthop(ctx->id, &ctx->u.nh, ctx->afi, + ctx->is_kernel_nh); + + if (nhe) { + if (ctx->id != nhe->id) + /* Duplicate but with different ID from + * the kernel */ + + /* The kernel allows duplicate nexthops + * as long as they have different IDs. + * We are ignoring those to prevent + * syncing problems with the kernel + * changes. + */ + flog_warn( + EC_ZEBRA_DUPLICATE_NHG_MESSAGE, + "Nexthop Group with ID (%d) is a duplicate, ignoring", + ctx->id); + else { + /* It actually created a new nhe */ + if (nhe->is_kernel_nh) { + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } + } + } else { + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find or create a nexthop hash entry for ID (%u)", + ctx->id); + return -1; + } + + return 0; +} + +static void nhg_ctx_process_finish(struct nhg_ctx *ctx) +{ + /* + * Just freeing for now, maybe do something more in the future + * based on flag. + */ + + if (ctx) + nhg_ctx_free(ctx); +} + +int nhg_ctx_process(struct nhg_ctx *ctx) +{ + int ret = 0; + + switch (nhg_ctx_get_op(ctx)) { + case NHG_CTX_OP_NEW: + ret = nhg_ctx_process_new(ctx); + break; + case NHG_CTX_OP_DEL: + case NHG_CTX_OP_NONE: + break; + } + + nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS)); + + nhg_ctx_process_finish(ctx); + + return ret; +} + +static int queue_add(struct nhg_ctx *ctx) +{ + /* If its queued or already processed do nothing */ + if (nhg_ctx_get_status(ctx)) + return 0; + + if (rib_queue_nhg_add(ctx)) { + nhg_ctx_set_status(ctx, NHG_CTX_FAILURE); + return -1; + } + + nhg_ctx_set_status(ctx, NHG_CTX_QUEUED); + + return 0; +} + +/* Kernel-side, you either get a single new nexthop or a array of ID's */ +int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + uint8_t count, vrf_id_t vrf_id, afi_t afi) +{ + // TODO: Can probably put table lookup + // here before queueing? And if deleted, re-send to kernel? + // ... Well, if changing the flags it probably needs to be queued + // still... + + struct nhg_ctx *ctx = NULL; + + ctx = nhg_ctx_new(); + + ctx->id = id; + ctx->vrf_id = vrf_id; + ctx->afi = afi; + ctx->is_kernel_nh = true; + ctx->count = count; + + if (count) + /* Copy over the array */ + memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp)); + else + ctx->u.nh = *nh; + + nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW); + + if (queue_add(ctx)) { + nhg_ctx_process_finish(ctx); + return -1; + } + + return 0; +} - nexthop_group_add_sorted(nhg, nh); - nhe = zebra_nhg_find(nhg, nh->vrf_id, afi, 0, NULL, false); +/* Rib-side, you get a nexthop group struct */ +struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, + struct nexthop_group *nhg, + vrf_id_t rt_vrf_id, afi_t rt_afi) +{ + struct nhg_hash_entry *nhe = NULL; + struct nhg_connected_head nhg_depends = {}; + // Defualt the nhe to the afi and vrf of the route + afi_t nhg_afi = rt_afi; + vrf_id_t nhg_vrf_id = rt_vrf_id; + + /* If its a group, create a dependency list */ + if (nhg && nhg->nexthop->next) { + struct nexthop *nh = NULL; + struct nexthop lookup = {0}; + struct nhg_hash_entry *depend = NULL; + + nhg_connected_head_init(&nhg_depends); + + for (ALL_NEXTHOPS_PTR(nhg, nh)) { + lookup = *nh; + /* Clear it, since its a group */ + lookup.next = NULL; + /* Use the route afi here, since a single nh */ + depend = zebra_nhg_find_nexthop(0, &lookup, rt_afi, + false); + nhg_connected_head_add(&nhg_depends, depend); + } - nexthop_group_delete(&nhg); + /* change the afi/vrf_id since its a group */ + nhg_afi = AFI_UNSPEC; + nhg_vrf_id = 0; + } + + nhe = zebra_nhg_find(id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, false); return nhe; } @@ -552,7 +734,7 @@ void zebra_nhg_free(void *arg) * * @nhe: Nexthop group hash entry */ -void zebra_nhg_release(struct nhg_hash_entry *nhe) +static void zebra_nhg_release(struct nhg_hash_entry *nhe) { zlog_debug("Releasing nexthop group with ID (%u)", nhe->id); @@ -564,6 +746,7 @@ void zebra_nhg_release(struct nhg_hash_entry *nhe) hash_release(zrouter.nhgs, nhe); hash_release(zrouter.nhgs_id, nhe); + zebra_nhg_free(nhe); } @@ -577,6 +760,8 @@ void zebra_nhg_release(struct nhg_hash_entry *nhe) */ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) { + nhe->refcnt--; + if (!zebra_nhg_depends_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; @@ -586,12 +771,8 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) } } - nhe->refcnt--; - - if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { + if (!nhe->is_kernel_nh && nhe->refcnt <= 0) zebra_nhg_uninstall_kernel(nhe); - zebra_nhg_release(nhe); - } } /** @@ -601,6 +782,8 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) */ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) { + nhe->refcnt++; + if (!zebra_nhg_depends_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; @@ -609,12 +792,34 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) zebra_nhg_increment_ref(rb_node_dep->nhe); } } +} - nhe->refcnt++; +static bool zebra_nhg_is_valid(struct nhg_hash_entry *nhe) +{ + if (nhe->flags & NEXTHOP_GROUP_VALID) + return true; + + return false; +} + +bool zebra_nhg_id_is_valid(uint32_t id) +{ + struct nhg_hash_entry *nhe = NULL; + bool is_valid = false; + + nhe = zebra_nhg_lookup_id(id); + + if (nhe) + is_valid = zebra_nhg_is_valid(nhe); + + return is_valid; } void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) { + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + /* Assuming uninstalled as well here */ + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); if (!zebra_nhg_dependents_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; @@ -624,10 +829,6 @@ void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) zebra_nhg_set_invalid(rb_node_dep->nhe); } } - - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - /* Assuming uninstalled as well here */ - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); } void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) @@ -1118,6 +1319,32 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) unsigned int prev_active, new_active; ifindex_t prev_index; uint8_t curr_active = 0; + afi_t rt_afi = AFI_UNSPEC; + + // TODO: Temporary until we get this function sorted out + // a little better. + // + if (re->nhe_id) { + struct nhg_hash_entry *nhe = NULL; + + nhe = zebra_nhg_lookup_id(re->nhe_id); + + if (nhe) { + if (!re->ng) { + /* This is its first time getting attached */ + zebra_nhg_increment_ref(nhe); + re->ng = nhe->nhg; + } + + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { + return 1; + } + } else + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find the nexthop hash entry for id=%u in a route entry", + re->nhe_id); + } UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); @@ -1158,6 +1385,40 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); } + // TODO: Update this when we have this function + // figured out a little better. + // + struct nhg_hash_entry *new_nhe = NULL; + + rt_afi = family2afi(rn->p.family); + // TODO: Add proto type here + + // TODO: Maybe make this a UPDATE message? + // Right now we are just creating a new one + // and deleting the old. + new_nhe = zebra_nhg_rib_find(0, re->ng, re->vrf_id, rt_afi); + + if (new_nhe && (re->nhe_id != new_nhe->id)) { + struct nhg_hash_entry *old_nhe = + zebra_nhg_lookup_id(re->nhe_id); + + /* It should point to the nhe nexthop group now */ + if (re->ng) + nexthop_group_free_delete(&re->ng); + re->ng = new_nhe->nhg; + re->nhe_id = new_nhe->id; + + zebra_nhg_increment_ref(new_nhe); + if (old_nhe) + zebra_nhg_decrement_ref(old_nhe); + + if (curr_active) { + SET_FLAG(new_nhe->flags, NEXTHOP_GROUP_VALID); + if (!new_nhe->is_kernel_nh) + zebra_nhg_install_kernel(new_nhe); + } + } + return curr_active; } @@ -1168,7 +1429,8 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) */ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) { - if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { nhe->is_kernel_nh = false; int ret = dplane_nexthop_add(nhe); switch (ret) { @@ -1209,9 +1471,11 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) break; case ZEBRA_DPLANE_REQUEST_SUCCESS: UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_release(nhe); break; } - } + } else + zebra_nhg_release(nhe); } /** @@ -1254,6 +1518,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) status = dplane_ctx_get_status(ctx); id = dplane_ctx_get_nhe_id(ctx); + nhe = zebra_nhg_lookup_id(id); if (nhe) { @@ -1268,6 +1533,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_DELETE: if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_release(nhe); } else { flog_err( EC_ZEBRA_DP_DELETE_FAIL, diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 1f8f63ad67..e287dacfdb 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -34,7 +34,7 @@ * It is designed to mimic the netlink nexthop_grp * struct in include/linux/nexthop.h */ -struct depend_info { +struct nh_grp { uint32_t id; uint8_t weight; }; @@ -98,6 +98,47 @@ struct nhg_connected { RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); + +enum nhg_ctx_op_e { + NHG_CTX_OP_NONE = 0, + NHG_CTX_OP_NEW, + NHG_CTX_OP_DEL, +}; + +enum nhg_ctx_result { + NHG_CTX_NONE = 0, + NHG_CTX_QUEUED, + NHG_CTX_SUCCESS, + NHG_CTX_FAILURE, +}; + +/* + * Context needed to queue nhg updates on the + * work queue. + */ +struct nhg_ctx { + + /* Unique ID */ + uint32_t id; + + vrf_id_t vrf_id; + afi_t afi; + bool is_kernel_nh; + + /* If its a group array, how many? */ + uint8_t count; + + /* Its either a single nexthop or an array of ID's */ + union { + struct nexthop nh; + struct nh_grp grp[MULTIPATH_NUM]; + } u; + + enum nhg_ctx_op_e op; + enum nhg_ctx_result status; +}; + + void zebra_nhg_init(void); void zebra_nhg_terminate(void); @@ -147,20 +188,31 @@ extern uint32_t zebra_nhg_id_key(const void *arg); extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); -extern struct nhg_hash_entry * -zebra_nhg_find(struct nexthop_group *nhg, vrf_id_t vrf_id, afi_t afi, - uint32_t id, struct nhg_connected_head *nhg_depends, - bool is_kernel_nh); +/* + * Process a context off of a queue. + * Specifically this should be from + * the rib meta queue. + */ +extern int nhg_ctx_process(struct nhg_ctx *ctx); -extern struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, - afi_t afi); +/* Find via kernel nh creation */ +extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, + struct nh_grp *grp, uint8_t count, + vrf_id_t vrf_id, afi_t afi); + +/* Find via route creation */ +extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, + struct nexthop_group *nhg, + vrf_id_t rt_vrf_id, + afi_t rt_afi); void zebra_nhg_free_members(struct nhg_hash_entry *nhe); void zebra_nhg_free(void *arg); -void zebra_nhg_release(struct nhg_hash_entry *nhe); void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); + +extern bool zebra_nhg_id_is_valid(uint32_t id); void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe); void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6fe87697b2..6276ed3478 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -56,7 +56,6 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_dplane.h" -#include "zebra/zebra_nhg.h" DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object"); @@ -79,34 +78,35 @@ static const struct { uint8_t distance; uint8_t meta_q_map; } route_info[ZEBRA_ROUTE_MAX] = { - [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 4}, - [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 0}, - [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 0}, - [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 1}, - [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 2}, - [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 2}, - [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 2}, - [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 2}, - [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 2}, - [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 3}, - [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 4}, - [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 2}, - [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 2}, - [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 4}, - [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 4}, - [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 1}, - [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 4}, - [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 3}, - [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 3}, - [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 3}, - [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 3}, - [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 3}, - [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 2}, - [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 4}, - [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 4}, - [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 4}, - [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 2}, - [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 4} + [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Uneeded for nhg's */, 0}, + [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 5}, + [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 1}, + [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 1}, + [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 2}, + [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 3}, + [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 3}, + [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 3}, + [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 3}, + [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 3}, + [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 4}, + [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 5}, + [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 3}, + [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 3}, + [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 5}, + [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 5}, + [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 2}, + [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 5}, + [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 4}, + [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 4}, + [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 4}, + [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 4}, + [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 4}, + [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 3}, + [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 5}, + [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 5}, + [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 5}, + [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 3}, + [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 5} /* Any new route type added to zebra, should be mirrored here */ /* no entry/default: 150 */ @@ -618,6 +618,16 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) rib_table_info_t *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); + // TODO: Might need to move this? + // It checks if the nhe is even valid + // before trying to uninstall it. If the + // nexthop is invalid/uninstalled, then + // this route is not in the kernel anymore + // most likely. + if (!zebra_nhg_id_is_valid(re->nhe_id)) + return; + + if (info->safi != SAFI_UNICAST) { UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) @@ -1082,6 +1092,12 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return current; } +/* Core function for processing nexthop group contexts's off metaq */ +static void rib_nhg_process(struct nhg_ctx *ctx) +{ + nhg_ctx_process(ctx); +} + /* Core function for processing routing information base. */ static void rib_process(struct route_node *rn) { @@ -2058,19 +2074,28 @@ done: dplane_ctx_fini(&ctx); } -/* Take a list of route_node structs and return 1, if there was a record - * picked from it and processed by rib_process(). Don't process more, - * than one RN record; operate only in the specified sub-queue. - */ -static unsigned int process_subq(struct list *subq, uint8_t qindex) +static void process_subq_nhg(struct listnode *lnode) { - struct listnode *lnode = listhead(subq); - struct route_node *rnode; - rib_dest_t *dest; - struct zebra_vrf *zvrf = NULL; + struct nhg_ctx *ctx = NULL; + uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; - if (!lnode) - return 0; + ctx = listgetdata(lnode); + + if (!ctx) + return; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("NHG Context id=%u dequeued from sub-queue %u", + ctx->id, qindex); + + rib_nhg_process(ctx); +} + +static void process_subq_route(struct listnode *lnode, uint8_t qindex) +{ + struct route_node *rnode = NULL; + rib_dest_t *dest = NULL; + struct zebra_vrf *zvrf = NULL; rnode = listgetdata(lnode); dest = rib_dest_from_rnode(rnode); @@ -2100,7 +2125,26 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) } #endif route_unlock_node(rnode); +} + +/* Take a list of route_node structs and return 1, if there was a record + * picked from it and processed by rib_process(). Don't process more, + * than one RN record; operate only in the specified sub-queue. + */ +static unsigned int process_subq(struct list *subq, uint8_t qindex) +{ + struct listnode *lnode = listhead(subq); + + if (!lnode) + return 0; + + if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map) + process_subq_nhg(lnode); + else + process_subq_route(lnode, qindex); + list_delete_node(subq, lnode); + return 1; } @@ -2158,11 +2202,14 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) * original metaqueue index value will win and we'll end up with * the route node enqueued once. */ -static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) +static int rib_meta_queue_add(struct meta_queue *mq, void *data) { + struct route_node *rn = NULL; struct route_entry *re = NULL, *curr_re = NULL; uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE; + rn = (struct route_node *)data; + RNODE_FOREACH_RE (rn, curr_re) { curr_qindex = route_info[curr_re->type].meta_q_map; @@ -2173,7 +2220,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) } if (!re) - return; + return -1; /* Invariant: at this point we always have rn->info set. */ if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, @@ -2182,7 +2229,7 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) rnode_debug(rn, re->vrf_id, "rn %p is already queued in sub-queue %u", (void *)rn, qindex); - return; + return -1; } SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex)); @@ -2193,26 +2240,37 @@ static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_DETAILED) rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u", (void *)rn, qindex); + + return 0; } -/* Add route_node to work queue and schedule processing */ -void rib_queue_add(struct route_node *rn) +static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) { - assert(rn); + struct nhg_ctx *ctx = NULL; + uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; - /* Pointless to queue a route_node with no RIB entries to add or remove - */ - if (!rnode_to_ribs(rn)) { - zlog_debug("%s: called for route_node (%p, %d) with no ribs", - __func__, (void *)rn, rn->lock); - zlog_backtrace(LOG_DEBUG); - return; - } + ctx = (struct nhg_ctx *)data; + + if (!ctx) + return -1; + listnode_add(mq->subq[qindex], ctx); + mq->size++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("NHG Context id=%u queued into sub-queue %u", + ctx->id, qindex); + + return 0; +} + +static int mq_add_handler(void *data, + int (*mq_add_func)(struct meta_queue *mq, void *data)) +{ if (zrouter.ribq == NULL) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: work_queue does not exist!", __func__); - return; + return -1; } /* @@ -2226,9 +2284,31 @@ void rib_queue_add(struct route_node *rn) if (work_queue_empty(zrouter.ribq)) work_queue_add(zrouter.ribq, zrouter.mq); - rib_meta_queue_add(zrouter.mq, rn); + return mq_add_func(zrouter.mq, data); +} - return; +/* Add route_node to work queue and schedule processing */ +int rib_queue_add(struct route_node *rn) +{ + assert(rn); + + /* Pointless to queue a route_node with no RIB entries to add or remove + */ + if (!rnode_to_ribs(rn)) { + zlog_debug("%s: called for route_node (%p, %d) with no ribs", + __func__, (void *)rn, rn->lock); + zlog_backtrace(LOG_DEBUG); + return -1; + } + + return mq_add_handler(rn, &rib_meta_queue_add); +} + +int rib_queue_nhg_add(struct nhg_ctx *ctx) +{ + assert(ctx); + + return mq_add_handler(ctx, &rib_meta_queue_nhg_add); } /* Create new meta queue. @@ -2411,9 +2491,12 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - nhe = zebra_nhg_lookup_id(re->nhe_id); - if (nhe) - zebra_nhg_decrement_ref(nhe); + if (re->nhe_id) { + nhe = zebra_nhg_lookup_id(re->nhe_id); + if (nhe) + zebra_nhg_decrement_ref(nhe); + } else if (re->ng) + nexthop_group_free_delete(&re->ng); nexthops_free(re->fib_ng.nexthop); @@ -2637,12 +2720,6 @@ 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 = NULL; - struct nhg_hash_entry *nhe = NULL; - struct nhg_connected_head nhg_depends = {0}; - /* Default to route afi */ - afi_t nhg_afi = afi; - /* Default to route vrf id */ - vrf_id_t nhg_vrf_id = re->vrf_id; int ret = 0; if (!re) @@ -2664,48 +2741,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (src_p) apply_mask_ipv6(src_p); - /* If its a group, create a dependency list */ - if (re->ng && re->ng->nexthop->next) { - struct nexthop *nh = NULL; - struct nexthop lookup = {0}; - struct nhg_hash_entry *depend = NULL; - - nhg_connected_head_init(&nhg_depends); - - for (ALL_NEXTHOPS_PTR(re->ng, nh)) { - lookup = *nh; - /* Clear it, since its a group */ - lookup.next = NULL; - /* Use the route afi here, since a single nh */ - depend = zebra_nhg_find_nexthop(&lookup, afi); - nhg_connected_head_add(&nhg_depends, depend); - } - - /* change the afi for group */ - nhg_afi = AFI_UNSPEC; - nhg_vrf_id = 0; - } - - // TODO: Add proto type here - nhe = zebra_nhg_find(re->ng, nhg_vrf_id, nhg_afi, re->nhe_id, - &nhg_depends, false); - - if (nhe) { - /* It should point to the nhe nexthop group now */ - if (re->ng) - nexthop_group_free_delete(&re->ng); - re->ng = nhe->nhg; - re->nhe_id = nhe->id; - zebra_nhg_increment_ref(nhe); - } else { - flog_err( - EC_ZEBRA_TABLE_LOOKUP_FAILED, - "Zebra failed to find or create a nexthop hash entry for id=%u in a route entry", - re->nhe_id); - nhg_connected_head_free(&nhg_depends); - } - - /* Set default distance by route type. */ if (re->distance == 0) re->distance = route_distance(re->type); @@ -3006,12 +3041,14 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->tag = tag; re->nhe_id = nhe_id; - re->ng = nexthop_group_new(); + if (!nhe_id) { + re->ng = nexthop_group_new(); - /* Add nexthop. */ - nexthop = nexthop_new(); - *nexthop = *nh; - route_entry_nexthop_add(re, nexthop); + /* Add nexthop. */ + nexthop = nexthop_new(); + *nexthop = *nh; + route_entry_nexthop_add(re, nexthop); + } return rib_add_multipath(afi, safi, p, src_p, re); } -- cgit v1.2.3 From 98cda54a9543ea125e5e1eea6621c453f407edb2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:27:40 -0700 Subject: zebra: Add recursive functionality to NHE's Add the ability to recursively resolve nexthop group hash entries and resolve them when sending to the kernel. When copying over nexthops into an NHE, copy resolved info as well. Signed-off-by: Stephen Worley --- lib/nexthop.h | 1 + lib/nexthop_group.c | 30 ++++- lib/nexthop_group.h | 4 + zebra/rt_netlink.c | 3 +- zebra/zebra_dplane.c | 27 ++--- zebra/zebra_nhg.c | 310 +++++++++++++++++++++++++++++++++++++-------------- zebra/zebra_nhg.h | 14 +++ zebra/zebra_rib.c | 44 ++++++++ 8 files changed, 328 insertions(+), 105 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/lib/nexthop.h b/lib/nexthop.h index 9dd5fc6fd3..5558e857f6 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -154,6 +154,7 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2); extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size); extern struct nexthop *nexthop_next(struct nexthop *nexthop); +extern struct nexthop *nexthop_recursive_next(struct nexthop *nexthop); extern unsigned int nexthop_level(struct nexthop *nexthop); /* Copies to an already allocated nexthop struct */ extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 463ab0b881..c9a8f1af51 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -81,6 +81,17 @@ uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg) return num; } +uint8_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg) +{ + struct nexthop *nhop; + uint8_t num = 0; + + for (nhop = nhg->nexthop; nhop; nhop = nhop->next) + num++; + + return num; +} + uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg) { struct nexthop *nhop; @@ -94,6 +105,20 @@ uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg) return num; } +uint8_t +nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg) +{ + struct nexthop *nhop; + uint8_t num = 0; + + for (nhop = nhg->nexthop; nhop; nhop = nhop->next) { + if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE)) + num++; + } + + return num; +} + struct nexthop *nexthop_exists(const struct nexthop_group *nhg, const struct nexthop *nh) { @@ -118,10 +143,11 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, if (!nhg1 && !nhg2) return false; - if (nexthop_group_nexthop_num(nhg1) != nexthop_group_nexthop_num(nhg2)) + if (nexthop_group_nexthop_num_no_recurse(nhg1) + != nexthop_group_nexthop_num_no_recurse(nhg2)) return false; - for (ALL_NEXTHOPS_PTR(nhg1, nh)) { + for (nh = nhg1->nexthop; nh; nh = nh->next) { if (!nexthop_exists(nhg2, nh)) return false; } diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index be6f50d8a0..57a5a97599 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -123,7 +123,11 @@ extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh); /* Return the number of nexthops in this nhg */ extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg); extern uint8_t +nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg); +extern uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg); +extern uint8_t +nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg); #ifdef __cplusplus } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5d2d407688..89fed59f76 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2025,7 +2025,8 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) */ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) { - int cmd, ret = 0; + int cmd = 0; + int ret = 0; switch (dplane_ctx_get_op(ctx)) { case DPLANE_OP_NH_DELETE: diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index f818ed5bc6..429d4c59a1 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1525,8 +1525,9 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, zns = zvrf->zns; dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE)); - if (re->nhe_id && zns->supports_nh) - ctx->u.rinfo.nhe.id = re->nhe_id; + if (re->nhe_id && zns->supports_nh) { + ctx->u.rinfo.nhe.id = zebra_nhg_get_resolved_id(re->nhe_id); + } /* Trying out the sequence number idea, so we can try to detect * when a result is stale. @@ -1571,23 +1572,11 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg); - if (!zebra_nhg_depends_is_empty(nhe)) { - struct nhg_connected *rb_node_dep = NULL; - uint8_t i = 0; - - // TODO: This doesn't work with depends being recursive - // resolved nh's as well. Yea, good luck future stephen - // this one... - - RB_FOREACH (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends) { - ctx->u.rinfo.nhe.nh_grp[i].id = rb_node_dep->nhe->id; - /* We aren't using weights for anything right now */ - ctx->u.rinfo.nhe.nh_grp[i].weight = 0; - i++; - } - ctx->u.rinfo.nhe.nh_grp_count = i; - } + /* If its a group, convert it to a grp array of ids */ + if (!zebra_nhg_depends_is_empty(nhe) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) + ctx->u.rinfo.nhe.nh_grp_count = + zebra_nhg_nhe2grp(ctx->u.rinfo.nhe.nh_grp, nhe); /* Extract ns info - can't use pointers to 'core' structs */ diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 94d41ba246..144decfbb5 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -101,6 +101,12 @@ bool nhg_connected_head_is_empty(const struct nhg_connected_head *head) return RB_EMPTY(nhg_connected_head, head); } +struct nhg_connected * +nhg_connected_head_root(const struct nhg_connected_head *head) +{ + return RB_ROOT(nhg_connected_head, head); +} + void nhg_connected_head_del(struct nhg_connected_head *head, struct nhg_hash_entry *depend) { @@ -128,6 +134,37 @@ void nhg_connected_head_add(struct nhg_connected_head *head, RB_INSERT(nhg_connected_head, head, new); } +struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe) +{ + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE) + && !zebra_nhg_depends_is_empty(nhe)) { + nhe = nhg_connected_head_root(&nhe->nhg_depends)->nhe; + return zebra_nhg_resolve(nhe); + } + + return nhe; +} + +uint32_t zebra_nhg_get_resolved_id(uint32_t id) +{ + struct nhg_hash_entry *nhe = NULL; + + nhe = zebra_nhg_lookup_id(id); + + if (!nhe) { + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to lookup a resolved nexthop hash entry id=%u", + id); + return id; + } + + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) + nhe = zebra_nhg_resolve(nhe); + + return nhe->id; +} + unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) { return nhg_connected_head_count(&nhe->nhg_depends); @@ -352,6 +389,10 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) const struct nhg_hash_entry *nhe1 = arg1; const struct nhg_hash_entry *nhe2 = arg2; + /* No matter what if they equal IDs, assume equal */ + if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id)) + return true; + if (nhe1->vrf_id != nhe2->vrf_id) return false; @@ -361,6 +402,10 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (!nexthop_group_equal(nhe1->nhg, nhe2->nhg)) return false; + if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg) + != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg)) + return false; + return true; } @@ -651,32 +696,44 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, return 0; } +static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) +{ + struct nexthop lookup = {0}; + + lookup = *nh; + /* Clear it, in case its a group */ + lookup.next = NULL; + lookup.prev = NULL; + return zebra_nhg_find_nexthop(0, &lookup, afi, false); +} + /* Rib-side, you get a nexthop group struct */ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, vrf_id_t rt_vrf_id, afi_t rt_afi) { struct nhg_hash_entry *nhe = NULL; + struct nhg_hash_entry *depend = NULL; struct nhg_connected_head nhg_depends = {}; + // Defualt the nhe to the afi and vrf of the route afi_t nhg_afi = rt_afi; vrf_id_t nhg_vrf_id = rt_vrf_id; - /* If its a group, create a dependency list */ - if (nhg && nhg->nexthop->next) { - struct nexthop *nh = NULL; - struct nexthop lookup = {0}; - struct nhg_hash_entry *depend = NULL; + if (!nhg) { + flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, + "No nexthop passed to zebra_nhg_rib_find()"); + return NULL; + } + if (nhg->nexthop->next) { nhg_connected_head_init(&nhg_depends); - for (ALL_NEXTHOPS_PTR(nhg, nh)) { - lookup = *nh; - /* Clear it, since its a group */ - lookup.next = NULL; - /* Use the route afi here, since a single nh */ - depend = zebra_nhg_find_nexthop(0, &lookup, rt_afi, - false); + /* If its a group, create a dependency tree */ + struct nexthop *nh = NULL; + + for (nh = nhg->nexthop; nh; nh = nh->next) { + depend = depends_find(nh, rt_afi); nhg_connected_head_add(&nhg_depends, depend); } @@ -686,7 +743,6 @@ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, } nhe = zebra_nhg_find(id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, false); - return nhe; } @@ -755,9 +811,10 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) if (!zebra_nhg_depends_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; + struct nhg_connected *tmp = NULL; - RB_FOREACH (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends) { + RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends, tmp) { zebra_nhg_decrement_ref(rb_node_dep->nhe); } } @@ -945,10 +1002,12 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop, /* * Given a nexthop we need to properly recursively resolve * the route. As such, do a table lookup to find and match - * if at all possible. Set the nexthop->ifindex as appropriate + * if at all possible. Set the nexthop->ifindex and resolved_id + * as appropriate */ static int nexthop_active(afi_t afi, struct route_entry *re, - struct nexthop *nexthop, struct route_node *top) + struct nexthop *nexthop, struct route_node *top, + uint32_t *resolved_id) { struct prefix p; struct route_table *table; @@ -1121,8 +1180,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re, nexthop_set_resolved(afi, newhop, nexthop); resolved = 1; } - if (resolved) + if (resolved) { re->nexthop_mtu = match->mtu; + *resolved_id = match->nhe_id; + } if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("\t%s: Recursion failed to find", __PRETTY_FUNCTION__); @@ -1141,9 +1202,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re, nexthop_set_resolved(afi, newhop, nexthop); resolved = 1; } - if (resolved) + if (resolved) { re->nexthop_mtu = match->mtu; - + *resolved_id = match->nhe_id; + } if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "\t%s: Static route unable to resolve", @@ -1175,11 +1237,15 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * appropriately as well. An existing route map can turn * (otherwise active) nexthop into inactive, but not vice versa. * + * If it finds a nexthop recursivedly, set the resolved_id + * to match that nexthop's nhg_hash_entry ID; + * * The return value is the final value of 'ACTIVE' flag. */ static unsigned nexthop_active_check(struct route_node *rn, struct route_entry *re, - struct nexthop *nexthop) + struct nexthop *nexthop, + uint32_t *resolved_id) { struct interface *ifp; route_map_result_t ret = RMAP_PERMITMATCH; @@ -1207,14 +1273,14 @@ static unsigned nexthop_active_check(struct route_node *rn, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active(AFI_IP, re, nexthop, rn)) + if (nexthop_active(AFI_IP, re, nexthop, rn, resolved_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6: family = AFI_IP6; - if (nexthop_active(AFI_IP6, re, nexthop, rn)) + if (nexthop_active(AFI_IP6, re, nexthop, rn, resolved_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -1231,7 +1297,8 @@ static unsigned nexthop_active_check(struct route_node *rn, else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } else { - if (nexthop_active(AFI_IP6, re, nexthop, rn)) + if (nexthop_active(AFI_IP6, re, nexthop, rn, + resolved_id)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -1305,41 +1372,24 @@ static unsigned nexthop_active_check(struct route_node *rn, */ int nexthop_active_update(struct route_node *rn, struct route_entry *re) { + struct nexthop_group new_grp = {}; struct nexthop *nexthop; union g_addr prev_src; unsigned int prev_active, new_active; ifindex_t prev_index; uint8_t curr_active = 0; - afi_t rt_afi = AFI_UNSPEC; - // TODO: Temporary until we get this function sorted out - // a little better. - // - if (re->nhe_id) { - struct nhg_hash_entry *nhe = NULL; + afi_t rt_afi = family2afi(rn->p.family); - nhe = zebra_nhg_lookup_id(re->nhe_id); - - if (nhe) { - if (!re->ng) { - /* This is its first time getting attached */ - zebra_nhg_increment_ref(nhe); - re->ng = nhe->nhg; - } + UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { - return 1; - } - } else - flog_err( - EC_ZEBRA_TABLE_LOOKUP_FAILED, - "Zebra failed to find the nexthop hash entry for id=%u in a route entry", - re->nhe_id); - } + /* Copy over the nexthops in current state */ + nexthop_group_copy(&new_grp, re->ng); - UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { + struct nhg_hash_entry *nhe = NULL; + uint32_t resolved_id = 0; - for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { /* No protocol daemon provides src and so we're skipping * tracking it */ prev_src = nexthop->rmap_src; @@ -1351,17 +1401,71 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) * a multipath perpsective should not be a data plane * decision point. */ - new_active = nexthop_active_check(rn, re, nexthop); + new_active = + nexthop_active_check(rn, re, nexthop, &resolved_id); + + /* + * Create the individual nexthop hash entries + * for the nexthops in the group + */ + + nhe = depends_find(nexthop, rt_afi); + + if (nhe && resolved_id) { + struct nhg_hash_entry *old_resolved = NULL; + struct nhg_hash_entry *new_resolved = NULL; + + /* If this was already resolved, get its resolved nhe */ + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) + old_resolved = zebra_nhg_resolve(nhe); + + /* + * We are going to do what is done in nexthop_active + * and clear whatever resolved nexthop may already be + * there. + */ + + zebra_nhg_depends_release(nhe); + nhg_connected_head_free(&nhe->nhg_depends); + + new_resolved = zebra_nhg_lookup_id(resolved_id); + + if (new_resolved) { + /* Add new resolved */ + zebra_nhg_depends_add(nhe, new_resolved); + zebra_nhg_dependents_add(new_resolved, nhe); + /* + * In case the new == old, we increment + * first and then decrement + */ + zebra_nhg_increment_ref(new_resolved); + if (old_resolved) + zebra_nhg_decrement_ref(old_resolved); + + SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); + } else + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to lookup a resolved nexthop hash entry id=%u", + resolved_id); + } + if (new_active - && nexthop_group_active_nexthop_num(re->ng) + && nexthop_group_active_nexthop_num(&new_grp) >= zrouter.multipath_num) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); new_active = 0; } - if (new_active) + if (nhe && new_active) { curr_active++; + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + if (!nhe->is_kernel_nh + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) + zebra_nhg_install_kernel(nhe); + } + /* Don't allow src setting on IPv6 addr for now */ if (prev_active != new_active || prev_index != nexthop->ifindex || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX @@ -1376,43 +1480,83 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); } - // TODO: Update this when we have this function - // figured out a little better. - // - struct nhg_hash_entry *new_nhe = NULL; - - rt_afi = family2afi(rn->p.family); - // TODO: Add proto type here - - // TODO: Maybe make this a UPDATE message? - // Right now we are just creating a new one - // and deleting the old. - new_nhe = zebra_nhg_rib_find(0, re->ng, re->vrf_id, rt_afi); - - if (new_nhe && (re->nhe_id != new_nhe->id)) { - struct nhg_hash_entry *old_nhe = - zebra_nhg_lookup_id(re->nhe_id); - - /* It should point to the nhe nexthop group now */ - if (re->ng) - nexthop_group_free_delete(&re->ng); - re->ng = new_nhe->nhg; - re->nhe_id = new_nhe->id; - - zebra_nhg_increment_ref(new_nhe); - if (old_nhe) - zebra_nhg_decrement_ref(old_nhe); - - if (curr_active) { - SET_FLAG(new_nhe->flags, NEXTHOP_GROUP_VALID); - if (!new_nhe->is_kernel_nh) - zebra_nhg_install_kernel(new_nhe); + if (CHECK_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)) { + struct nhg_hash_entry *new_nhe = NULL; + // TODO: Add proto type here + + new_nhe = zebra_nhg_rib_find(0, &new_grp, re->vrf_id, rt_afi); + + if (new_nhe && (re->nhe_id != new_nhe->id)) { + struct nhg_hash_entry *old_nhe = + zebra_nhg_lookup_id(re->nhe_id); + + re->ng = new_nhe->nhg; + re->nhe_id = new_nhe->id; + + zebra_nhg_increment_ref(new_nhe); + if (old_nhe) + zebra_nhg_decrement_ref(old_nhe); } } + if (curr_active) { + struct nhg_hash_entry *nhe = NULL; + + nhe = zebra_nhg_lookup_id(re->nhe_id); + + if (nhe) { + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + if (!nhe->is_kernel_nh + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) + zebra_nhg_install_kernel(nhe); + } else + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Active update on NHE id=%u that we do not have in our tables", + re->nhe_id); + } + + /* + * Do not need these nexthops anymore since they + * were either copied over into an nhe or not + * used at all. + */ + nexthops_free(new_grp.nexthop); return curr_active; } +/* Convert a nhe into a group array */ +uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) +{ + struct nhg_connected *rb_node_dep = NULL; + struct nhg_hash_entry *depend = NULL; + uint8_t i = 0; + + RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe->nhg_depends) { + depend = rb_node_dep->nhe; + + /* + * If its recursive, use its resolved nhe in the group + */ + if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) { + depend = zebra_nhg_resolve(depend); + if (!depend) { + flog_err( + EC_ZEBRA_NHG_FIB_UPDATE, + "Failed to recursively resolve Nexthop Hash Entry id=%u in the group id=%u", + depend->id, nhe->id); + continue; + } + } + + grp[i].id = depend->id; + /* We aren't using weights for anything right now */ + grp[i].weight = 0; + i++; + } + return i; +} + /** * zebra_nhg_install_kernel() - Install Nexthop Group hash entry into kernel * diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index e287dacfdb..c6ac7d4706 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -88,6 +88,10 @@ struct nhg_hash_entry { * The NEXTHOP_GROUP_VALID flag should also be set by this point. */ #define NEXTHOP_GROUP_QUEUED 0x4 +/* + * Is this a nexthop that is recursively resolved? + */ +#define NEXTHOP_GROUP_RECURSIVE 0x8 }; /* Abstraction for connected trees */ @@ -151,6 +155,8 @@ extern unsigned int nhg_connected_head_count(const struct nhg_connected_head *head); extern void nhg_connected_head_free(struct nhg_connected_head *head); extern bool nhg_connected_head_is_empty(const struct nhg_connected_head *head); +extern struct nhg_connected * +nhg_connected_head_root(const struct nhg_connected_head *head); extern void nhg_connected_head_del(struct nhg_connected_head *head, struct nhg_hash_entry *nhe); extern void nhg_connected_head_add(struct nhg_connected_head *head, @@ -160,6 +166,11 @@ extern void nhg_connected_head_add(struct nhg_connected_head *head, * NHE abstracted tree functions. * Use these where possible instead of the direct ones access ones. */ + + +extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe); +extern uint32_t zebra_nhg_get_resolved_id(uint32_t id); + /* Depends */ extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); extern bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe); @@ -218,6 +229,9 @@ void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp); extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); +extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, + struct nhg_hash_entry *nhe); + void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6276ed3478..438923e232 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2717,6 +2717,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id) int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re) { + struct nhg_hash_entry *nhe = NULL; struct route_table *table; struct route_node *rn; struct route_entry *same = NULL; @@ -2736,6 +2737,49 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, return 0; } + if (re->nhe_id) { + nhe = zebra_nhg_lookup_id(re->nhe_id); + + if (!nhe) { + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find the nexthop hash entry for id=%u in a route entry", + re->nhe_id); + XFREE(MTYPE_RE, re); + return -1; + } + } else { + nhe = zebra_nhg_rib_find(0, re->ng, re->vrf_id, afi); + + /* + * The nexthops got copied over into an nhe, + * so free them now. + */ + nexthop_group_free_delete(&re->ng); + + if (!nhe) { + char buf[PREFIX_STRLEN] = ""; + char buf2[PREFIX_STRLEN] = ""; + + flog_err( + EC_ZEBRA_TABLE_LOOKUP_FAILED, + "Zebra failed to find or create a nexthop hash entry for %s%s%s", + prefix2str(p, buf, sizeof(buf)), + src_p ? " from " : "", + src_p ? prefix2str(src_p, buf2, sizeof(buf2)) + : ""); + + XFREE(MTYPE_RE, re); + return -1; + } + + re->nhe_id = nhe->id; + } + + /* Attach the re to the nhe's nexthop group */ + zebra_nhg_increment_ref(nhe); + re->ng = nhe->nhg; + /* Make it sure prefixlen is applied to the prefix. */ apply_mask(p); if (src_p) -- cgit v1.2.3 From 144a1b34dfc37fdd1174e7a2f150f2315730d8f7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:26:20 -0700 Subject: zebra: Put NHE ref updating into a function When the referenced NHE changes for a route_entry, use this function to handle it. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 33 ++++++++++++++++++++++----------- zebra/zebra_nhg.h | 3 +++ zebra/zebra_rib.c | 5 +---- 3 files changed, 26 insertions(+), 15 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index f43aa2f31e..1fd4ec4a9c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1493,17 +1493,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) new_nhe = zebra_nhg_rib_find(0, &new_grp, re->vrf_id, rt_afi); - if (new_nhe && (re->nhe_id != new_nhe->id)) { - struct nhg_hash_entry *old_nhe = - zebra_nhg_lookup_id(re->nhe_id); - - re->ng = new_nhe->nhg; - re->nhe_id = new_nhe->id; - - zebra_nhg_increment_ref(new_nhe); - if (old_nhe) - zebra_nhg_decrement_ref(old_nhe); - } + zebra_nhg_re_update_ref(re, new_nhe); } if (curr_active) { @@ -1532,6 +1522,27 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) return curr_active; } +int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) +{ + struct nhg_hash_entry *old = NULL; + + if (!new) + return -1; + + if (re->nhe_id != new->id) { + old = zebra_nhg_lookup_id(re->nhe_id); + + re->ng = new->nhg; + re->nhe_id = new->id; + + zebra_nhg_increment_ref(new); + if (old) + zebra_nhg_decrement_ref(old); + } + + return 0; +} + /* Convert a nhe into a group array */ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) { diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index c6ac7d4706..ef8b2730fb 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -229,6 +229,9 @@ void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp); extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); +extern int zebra_nhg_re_update_ref(struct route_entry *re, + struct nhg_hash_entry *nhe); + extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 438923e232..8fe673cb31 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2772,13 +2772,10 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, XFREE(MTYPE_RE, re); return -1; } - - re->nhe_id = nhe->id; } /* Attach the re to the nhe's nexthop group */ - zebra_nhg_increment_ref(nhe); - re->ng = nhe->nhg; + zebra_nhg_re_update_ref(re, nhe); /* Make it sure prefixlen is applied to the prefix. */ apply_mask(p); -- cgit v1.2.3 From 6df591527f8de78378e24096de6e78f42797b737 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:58:02 -0700 Subject: zebra: Remove route only if NHE is installed check Only remove a route if the nexthop it is using is still installed. If a nexthop object is removed from the kernel, all routes referencing it will be removed from the kernel. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 22 ++++++++++++++++++++-- zebra/zebra_rib.c | 10 ---------- 2 files changed, 20 insertions(+), 12 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 429d4c59a1..239988b3ab 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1525,9 +1525,24 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, zns = zvrf->zns; dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE)); +#ifdef HAVE_NETLINK if (re->nhe_id && zns->supports_nh) { ctx->u.rinfo.nhe.id = zebra_nhg_get_resolved_id(re->nhe_id); + + /* + * It checks if the nhe is even installed + * before trying to uninstall it. If the + * nexthop is uninstalled and the kernel + * is using nexthop objects, this route + * has already been uninstalled. + */ + if (!CHECK_FLAG(zebra_nhg_lookup_id(ctx->u.rinfo.nhe.id)->flags, + NEXTHOP_GROUP_INSTALLED)) { + ret = ENOENT; + goto done; + } } +#endif /* HAVE_NETLINK */ /* Trying out the sequence number idea, so we can try to detect * when a result is stale. @@ -1836,8 +1851,11 @@ dplane_route_update_internal(struct route_node *rn, if (ret == AOK) result = ZEBRA_DPLANE_REQUEST_QUEUED; else { - atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1, - memory_order_relaxed); + if (ret == ENOENT) + result = ZEBRA_DPLANE_REQUEST_SUCCESS; + else + atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, + 1, memory_order_relaxed); if (ctx) dplane_ctx_free(&ctx); } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8fe673cb31..0258c24090 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -618,16 +618,6 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) rib_table_info_t *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); - // TODO: Might need to move this? - // It checks if the nhe is even valid - // before trying to uninstall it. If the - // nexthop is invalid/uninstalled, then - // this route is not in the kernel anymore - // most likely. - if (!zebra_nhg_id_is_valid(re->nhe_id)) - return; - - if (info->safi != SAFI_UNICAST) { UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) -- cgit v1.2.3 From 7f997721693c63afcdf1d23f7449f8acbbe282d1 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 2 Jul 2019 01:16:48 -0400 Subject: zebra: Use nexthop/interface vrf, not the routes When hashing/creating the NHE, use the nexthops vrf as its source of data. This is gotten directly from an interface and should not come from a route. Signed-off-by: Stephen Worley --- zebra/zebra_mpls.c | 5 ++--- zebra/zebra_nhg.c | 18 ++++-------------- zebra/zebra_nhg.h | 6 ++---- zebra/zebra_rib.c | 2 +- 4 files changed, 9 insertions(+), 22 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index cbbb02be35..42d8c70f49 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2658,7 +2658,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, } if (found) { - nhe = zebra_nhg_rib_find(0, &new_grp, re->vrf_id, afi); + nhe = zebra_nhg_rib_find(0, &new_grp, afi); zebra_nhg_re_update_ref(re, nhe); @@ -2922,8 +2922,7 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) { - nhe = zebra_nhg_rib_find(0, &new_grp, - re->vrf_id, afi); + nhe = zebra_nhg_rib_find(0, &new_grp, afi); zebra_nhg_re_update_ref(re, nhe); } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 04a11dfcb6..8592e6500d 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -663,9 +663,8 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) } /* Rib-side, you get a nexthop group struct */ -struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, - struct nexthop_group *nhg, - vrf_id_t rt_vrf_id, afi_t rt_afi) +struct nhg_hash_entry * +zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) { struct nhg_hash_entry *nhe = NULL; struct nhg_hash_entry *depend = NULL; @@ -673,7 +672,7 @@ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, /* Defualt the nhe to the afi and vrf of the route */ afi_t nhg_afi = rt_afi; - vrf_id_t nhg_vrf_id = rt_vrf_id; + vrf_id_t nhg_vrf_id = nhg->nexthop->vrf_id; if (!nhg) { flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, @@ -695,15 +694,6 @@ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, /* change the afi/vrf_id since its a group */ nhg_afi = AFI_UNSPEC; nhg_vrf_id = 0; - } else { - /* - * If the vrf_id on the nexthop does not match - * the route one, use it instead. - */ - vrf_id_t nh_vrf_id = nhg->nexthop->vrf_id; - - if (nh_vrf_id && nh_vrf_id != rt_vrf_id) - nhg_vrf_id = nh_vrf_id; } if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, @@ -1413,7 +1403,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) struct nhg_hash_entry *new_nhe = NULL; // TODO: Add proto type here - new_nhe = zebra_nhg_rib_find(0, &new_grp, re->vrf_id, rt_afi); + new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi); zebra_nhg_re_update_ref(re, new_nhe); } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 31a2a020a0..ff2c73433a 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -212,10 +212,8 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, vrf_id_t vrf_id, afi_t afi); /* Find via route creation */ -extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, - struct nexthop_group *nhg, - vrf_id_t rt_vrf_id, - afi_t rt_afi); +extern struct nhg_hash_entry * +zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi); void zebra_nhg_free_members(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0258c24090..6be91da54a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2739,7 +2739,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, return -1; } } else { - nhe = zebra_nhg_rib_find(0, re->ng, re->vrf_id, afi); + nhe = zebra_nhg_rib_find(0, re->ng, afi); /* * The nexthops got copied over into an nhe, -- cgit v1.2.3 From 8dfbc657247d58e9888b7b04b8948558c1218e03 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:14:32 -0400 Subject: zebra: Install the nhe along with the route Move the installation of an nhe out of nexthop_active_update() and into the rib install path. So, only install the nhe when a route using it is being installed. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 7 ++----- zebra/zebra_rib.c | 8 ++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 13ea902543..a28f183895 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1398,12 +1398,9 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) nhe = zebra_nhg_lookup_id(re->nhe_id); - if (nhe) { + if (nhe) SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - if (!nhe->is_kernel_nh - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) - zebra_nhg_install_kernel(nhe); - } else + else flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, "Active update on NHE id=%u that we do not have in our tables", diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6be91da54a..67b4afb3a5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -519,6 +519,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); const struct prefix *p, *src_p; enum zebra_dplane_result ret; + struct nhg_hash_entry *nhe; rib_dest_t *dest = rib_dest_from_rnode(rn); @@ -545,6 +546,13 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, } } + /* + * Install the resolved nexthop object first. + */ + nhe = zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id)); + if (!nhe->is_kernel_nh) + zebra_nhg_install_kernel(nhe); + /* * If this is a replace to a new RE let the originator of the RE * know that they've lost -- cgit v1.2.3 From f429bd1b24e92433c8cd3c6869953a45aee57b1e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 11:45:19 -0400 Subject: zebra: Move resolve/add depend install into api Move the resolving and installing of a single nhg_hash_entry into the install function itself, rather than letting zebra_rib handle it. Further, ensure depends are installed/queued before installing a group. The ordering should be find here since only one thread will call this API. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 10 ++++++++++ zebra/zebra_rib.c | 5 +---- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index a28f183895..5179533e75 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1475,6 +1475,16 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) { + struct nhg_connected *rb_node_dep = NULL; + + /* Resolve it first */ + nhe = zebra_nhg_resolve(nhe); + + /* Make sure all depends are installed/queued */ + frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + zebra_nhg_install_kernel(rb_node_dep->nhe); + } + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { nhe->is_kernel_nh = false; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 67b4afb3a5..6827be7072 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -519,7 +519,6 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); const struct prefix *p, *src_p; enum zebra_dplane_result ret; - struct nhg_hash_entry *nhe; rib_dest_t *dest = rib_dest_from_rnode(rn); @@ -549,9 +548,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, /* * Install the resolved nexthop object first. */ - nhe = zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id)); - if (!nhe->is_kernel_nh) - zebra_nhg_install_kernel(nhe); + zebra_nhg_install_kernel(zebra_nhg_lookup_id(re->nhe_id)); /* * If this is a replace to a new RE let the originator of the RE -- cgit v1.2.3 From 4b87c90d58a04650d8bc4316115c3233236431a0 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:26:29 -0400 Subject: zebra: TODO for handling upper level nhe_id passing We need to handle refcnt differently if we ever start making upper level protocols aware of nhg_hash_entry IDs. Signed-off-by: Stephen Worley --- zebra/zebra_rib.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6827be7072..c89033b18c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2769,7 +2769,13 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, } } - /* Attach the re to the nhe's nexthop group */ + /* + * Attach the re to the nhe's nexthop group. + * + * TODO: This will need to change when we start getting IDs from upper + * level protocols, as the refcnt might be wrong, since it checks + * if old_id != new_id. + */ zebra_nhg_re_update_ref(re, nhe); /* Make it sure prefixlen is applied to the prefix. */ -- cgit v1.2.3 From 38e40db1c9695786d41a85661e313ce5a207866f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 1 Aug 2019 14:07:04 -0400 Subject: zebra: Sweep our nexthop objects out on restart On restart, if we failed to remove any nexthop objects due to a kill -9 or such event, sweep them if we aren't using them. Add a proto field to handle this and remove the is_kernel bool. Add a dupicate flag that indicates this nexthop group is only present in our ID hashtable. It is a dupicate nexthop we received from the kernel, therefore we cannot hash on it. Make the idcounter globally accessible so that kernel updates increment it as soon as we receive them, not when we handle them. Signed-off-by: Stephen Worley --- zebra/if_netlink.c | 3 +- zebra/rt_netlink.c | 23 +++- zebra/zebra_dplane.c | 9 +- zebra/zebra_dplane.h | 2 +- zebra/zebra_nhg.c | 302 ++++++++++++++++++++++++++++++++++++--------------- zebra/zebra_nhg.h | 31 ++++-- zebra/zebra_rib.c | 1 + zebra/zebra_router.c | 7 +- zebra/zebra_router.h | 1 + 9 files changed, 269 insertions(+), 110 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8c2caed1b0..44249d7dd1 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1489,9 +1489,8 @@ void interface_list(struct zebra_ns *zns) */ zlog_debug("Nexthop objects disabled on this kernel"); zns->supports_nh = false; - } else { + } else zns->supports_nh = true; - } interface_addr_lookup_netlink(zns); } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c6f15aef2a..3e913a7f5f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -188,7 +188,7 @@ static inline int zebra2proto(int proto) proto = RTPROT_OPENFABRIC; break; case ZEBRA_ROUTE_TABLE: - case ZEBRA_NHG: + case ZEBRA_ROUTE_NHG: proto = RTPROT_ZEBRA; break; default: @@ -208,7 +208,7 @@ static inline int zebra2proto(int proto) return proto; } -static inline int proto2zebra(int proto, int family) +static inline int proto2zebra(int proto, int family, bool is_nexthop) { switch (proto) { case RTPROT_BABEL: @@ -252,6 +252,12 @@ static inline int proto2zebra(int proto, int family) case RTPROT_OPENFABRIC: proto = ZEBRA_ROUTE_OPENFABRIC; break; + case RTPROT_ZEBRA: + if (is_nexthop) { + proto = ZEBRA_ROUTE_NHG; + break; + } + /* Intentional fall thru */ default: /* * When a user adds a new protocol this will show up @@ -589,7 +595,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, /* Route which inserted by Zebra. */ if (is_selfroute(rtm->rtm_protocol)) { flags |= ZEBRA_FLAG_SELFROUTE; - proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family); + proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false); } if (tb[RTA_OIF]) index = *(int *)RTA_DATA(tb[RTA_OIF]); @@ -2001,7 +2007,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) // TODO: Handle Encap } - req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_type(ctx)); + req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx)); } else if (cmd != RTM_DELNEXTHOP) { flog_err( @@ -2243,10 +2249,12 @@ static int netlink_nexthop_process_group(struct rtattr **tb, return count; } +#if 0 // TODO: Need type for something? zlog_debug("Nexthop group type: %d", *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE]))); +#endif for (int i = 0; i < count; i++) { z_grp[i].id = n_grp[i].id; @@ -2270,6 +2278,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* nexthop group id */ uint32_t id; unsigned char family; + int type; afi_t afi = AFI_UNSPEC; vrf_id_t vrf_id = 0; struct interface *ifp = NULL; @@ -2311,9 +2320,10 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) id = *((uint32_t *)RTA_DATA(tb[NHA_ID])); family = nhm->nh_family; - afi = family2afi(family); + type = proto2zebra(nhm->nh_protocol, 0, true); + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s ID (%u) %s NS %u", nl_msg_type_to_str(h->nlmsg_type), id, @@ -2363,7 +2373,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) // Gotta figure that one out. - if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi)) + if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi, + type, startup)) return -1; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 0e89ba3a27..e2c7bd7635 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -73,7 +73,7 @@ struct dplane_nexthop_info { uint32_t id; afi_t afi; vrf_id_t vrf_id; - bool is_kernel_nh; + int type; struct nexthop_group ng; struct nh_grp nh_grp[MULTIPATH_NUM]; @@ -1077,10 +1077,10 @@ vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.nhe.vrf_id; } -bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx) +int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rinfo.nhe.is_kernel_nh; + return ctx->u.rinfo.nhe.type; } const struct nexthop_group * @@ -1577,13 +1577,12 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->u.rinfo.zd_type = ZEBRA_ROUTE_TABLE; /* Copy over nhe info */ ctx->u.rinfo.nhe.id = nhe->id; ctx->u.rinfo.nhe.afi = nhe->afi; ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id; - ctx->u.rinfo.nhe.is_kernel_nh = nhe->is_kernel_nh; + ctx->u.rinfo.nhe.type = nhe->type; nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index d0fde958e4..fede3bfcca 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -279,7 +279,7 @@ const struct nexthop_group *dplane_ctx_get_old_ng( uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx); afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx); vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx); -bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx); const struct nexthop_group * dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx); const struct nh_grp * diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3589c0e7b7..fb9e913590 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -46,11 +46,17 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context"); +/* id counter to keep in sync with kernel */ +uint32_t id_counter; + static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi); static void depends_add(struct nhg_connected_tree_head *head, struct nhg_hash_entry *depend); -static void depends_find_add(struct nhg_connected_tree_head *head, - struct nexthop *nh, afi_t afi); +static struct nhg_hash_entry * +depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, + afi_t afi); +static struct nhg_hash_entry * +depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id); static void depends_decrement_free(struct nhg_connected_tree_head *head); @@ -273,26 +279,18 @@ int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) return 0; } - -static void *zebra_nhg_alloc(void *arg) +static void +zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, + struct nhg_connected_tree_head nhg_depends) { - struct nhg_hash_entry *nhe; - struct nhg_hash_entry *copy = arg; struct nhg_connected *rb_node_dep = NULL; - nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry)); - - nhe->id = copy->id; - nhe->nhg_depends = copy->nhg_depends; - - nhe->nhg = nexthop_group_new(); - nexthop_group_copy(nhe->nhg, copy->nhg); - - nhe->vrf_id = copy->vrf_id; - nhe->afi = copy->afi; - nhe->refcnt = 0; - nhe->is_kernel_nh = copy->is_kernel_nh; - nhe->dplane_ref = zebra_router_get_next_sequence(); + /* This has been allocated higher above in the stack. Could probably + * re-allocate and free the old stuff but just using the same memory + * for now. Otherwise, their might be a time trade-off for repeated + * alloc/frees as startup. + */ + nhe->nhg_depends = nhg_depends; /* Attach backpointer to anything that it depends on */ zebra_nhg_dependents_init(nhe); @@ -318,8 +316,37 @@ static void *zebra_nhg_alloc(void *arg) nhe->nhg->nexthop->ifindex, nhe->vrf_id, nhe->id); } +} + +static struct nhg_hash_entry *zebra_nhg_copy(struct nhg_hash_entry *copy, + uint32_t id) +{ + struct nhg_hash_entry *nhe; + + nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry)); + + nhe->id = id; + + nhe->nhg = nexthop_group_new(); + nexthop_group_copy(nhe->nhg, copy->nhg); + + nhe->vrf_id = copy->vrf_id; + nhe->afi = copy->afi; + nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG; + nhe->refcnt = 0; + nhe->dplane_ref = zebra_router_get_next_sequence(); + + return nhe; +} + +/* Allocation via hash handler */ +static void *zebra_nhg_hash_alloc(void *arg) +{ + struct nhg_hash_entry *nhe = NULL; + struct nhg_hash_entry *copy = arg; - /* Add to id table as well */ + nhe = zebra_nhg_copy(copy, copy->id); + zebra_nhg_connect_depends(nhe, copy->nhg_depends); zebra_nhg_insert_id(nhe); return nhe; @@ -391,24 +418,24 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, * how to adapt this to our code in * the future. */ - depend = zebra_nhg_lookup_id(grp[i].id); - if (depend) { - nhg_connected_tree_add_nhe(depends, depend); - /* - * If this is a nexthop with its own group - * dependencies, add them as well. Not sure its - * even possible to have a group within a group - * in the kernel. - */ + depend = depends_find_id_add(depends, grp[i].id); - copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, - NULL); - } else { + if (!depend) { flog_err( EC_ZEBRA_NHG_SYNC, "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table", grp[i].id); + return; } + + /* + * If this is a nexthop with its own group + * dependencies, add them as well. Not sure its + * even possible to have a group within a group + * in the kernel. + */ + + copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, NULL); } } @@ -416,29 +443,22 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, struct nexthop_group *nhg, struct nhg_connected_tree_head *nhg_depends, - vrf_id_t vrf_id, afi_t afi, bool is_kernel_nh) + vrf_id_t vrf_id, afi_t afi, int type) { - /* id counter to keep in sync with kernel */ - static uint32_t id_counter = 0; - struct nhg_hash_entry lookup = {}; uint32_t old_id_counter = id_counter; bool created = false; - if (id > id_counter) { - /* Increase our counter so we don't try to create - * an ID that already exists - */ - id_counter = id; - lookup.id = id; - } else - lookup.id = ++id_counter; + /* + * If it has an id at this point, we must have gotten it from the kernel + */ + lookup.id = id ? id : ++id_counter; lookup.afi = afi; lookup.vrf_id = vrf_id; - lookup.is_kernel_nh = is_kernel_nh; + lookup.type = type; lookup.nhg = nhg; if (nhg_depends) @@ -454,7 +474,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, id_counter = old_id_counter; if (!(*nhe)) { - (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); + (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc); created = true; } @@ -475,8 +495,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, /* Find/create a single nexthop */ static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id, - struct nexthop *nh, afi_t afi, - bool is_kernel_nh) + struct nexthop *nh, afi_t afi, int type) { struct nexthop_group nhg = {}; struct nhg_connected_tree_head nhg_depends = {}; @@ -489,8 +508,7 @@ static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id, handle_recursive_depend(&nhg_depends, nh->resolved, afi); } - if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, - is_kernel_nh)) { + if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, 0)) { created = false; depends_decrement_free(&nhg_depends); } else { @@ -535,6 +553,29 @@ static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx) return ctx->op; } +static bool zebra_nhg_contains_dup(struct nhg_hash_entry *nhe) +{ + struct nhg_connected *rb_node_dep = NULL; + + frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + if (CHECK_FLAG(rb_node_dep->nhe->flags, + NEXTHOP_GROUP_DUPLICATE)) + return true; + } + + return false; +} + +static void zebra_nhg_set_dup(struct nhg_hash_entry *nhe) +{ + SET_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + + flog_warn(EC_ZEBRA_DUPLICATE_NHG_MESSAGE, + "Nexthop Group with ID (%d) is a duplicate, ignoring", + nhe->id); +} + static int nhg_ctx_process_new(struct nhg_ctx *ctx) { struct nexthop_group *nhg = NULL; @@ -546,17 +587,19 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) zebra_nhg_process_grp(nhg, &nhg_depends, ctx->u.grp, ctx->count); if (!zebra_nhg_find(&nhe, ctx->id, nhg, &nhg_depends, - ctx->vrf_id, ctx->afi, true)) - nhg_connected_tree_free(&nhg_depends); + ctx->vrf_id, ctx->type, ctx->afi)) + depends_decrement_free(&nhg_depends); /* These got copied over in zebra_nhg_alloc() */ nexthop_group_free_delete(&nhg); - } else if (!zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi, - ctx->is_kernel_nh)) - nhg_connected_tree_free(&nhg_depends); + } else + zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi, + ctx->type); if (nhe) { - if (ctx->id != nhe->id) + if (ctx->id != nhe->id) { + struct nhg_hash_entry *kernel_nhe = NULL; + /* Duplicate but with different ID from * the kernel */ @@ -566,17 +609,25 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) * We are ignoring those to prevent * syncing problems with the kernel * changes. + * + * We maintain them *ONLY* in the ID hash table to + * track them. + */ + + kernel_nhe = zebra_nhg_copy(nhe, ctx->id); + zebra_nhg_insert_id(kernel_nhe); + zebra_nhg_set_dup(kernel_nhe); + } else if (zebra_nhg_contains_dup(nhe)) { + /* The group we got contains a duplciate depend, + * so lets mark this group as a dup as well and release + * it from the non-ID hash. */ - flog_warn( - EC_ZEBRA_DUPLICATE_NHG_MESSAGE, - "Nexthop Group with ID (%d) is a duplicate, ignoring", - ctx->id); - else { + hash_release(zrouter.nhgs, nhe); + zebra_nhg_set_dup(nhe); + } else { /* It actually created a new nhe */ - if (nhe->is_kernel_nh) { - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - } + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); } } else { flog_err( @@ -638,7 +689,8 @@ static int queue_add(struct nhg_ctx *ctx) /* Kernel-side, you either get a single new nexthop or a array of ID's */ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, - uint8_t count, vrf_id_t vrf_id, afi_t afi) + uint8_t count, vrf_id_t vrf_id, afi_t afi, int type, + int startup) { // TODO: Can probably put table lookup // here before queueing? And if deleted, re-send to kernel? @@ -647,12 +699,18 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, struct nhg_ctx *ctx = NULL; + if (id > id_counter) + /* Increase our counter so we don't try to create + * an ID that already exists + */ + id_counter = id; + ctx = nhg_ctx_new(); ctx->id = id; ctx->vrf_id = vrf_id; ctx->afi = afi; - ctx->is_kernel_nh = true; + ctx->type = type; ctx->count = count; if (count) @@ -663,6 +721,13 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW); + /* Under statup conditions, we need to handle them immediately + * like we do for routes. Otherwise, we are going to get a route + * with a nhe_id that we have not handled. + */ + if (startup) + return nhg_ctx_process(ctx); + if (queue_add(ctx)) { nhg_ctx_process_finish(ctx); return -1; @@ -685,7 +750,7 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) lookup->next = NULL; lookup->prev = NULL; - zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, false); + zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, 0); nexthops_free(lookup); @@ -699,13 +764,27 @@ static void depends_add(struct nhg_connected_tree_head *head, zebra_nhg_increment_ref(depend); } -static void depends_find_add(struct nhg_connected_tree_head *head, - struct nexthop *nh, afi_t afi) +static struct nhg_hash_entry * +depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, + afi_t afi) { struct nhg_hash_entry *depend = NULL; depend = depends_find(nh, afi); depends_add(head, depend); + + return depend; +} + +static struct nhg_hash_entry * +depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id) +{ + struct nhg_hash_entry *depend = NULL; + + depend = zebra_nhg_lookup_id(id); + depends_add(head, depend); + + return depend; } static void depends_decrement_free(struct nhg_connected_tree_head *head) @@ -752,7 +831,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) } if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, - false)) + 0)) depends_decrement_free(&nhg_depends); else if (recursive) SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); @@ -775,12 +854,21 @@ void zebra_nhg_free(void *arg) nhe = (struct nhg_hash_entry *)arg; + if (nhe->refcnt) + zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt); + zebra_nhg_free_members(nhe); XFREE(MTYPE_NHG, nhe); } -static void zebra_nhg_release(struct nhg_hash_entry *nhe) +/* + * Release from the non-ID hash'd table. + * + * Basically, we are saying don't let routes use this anymore, + * because we are removing it. + */ +static void zebra_nhg_release_no_id(struct nhg_hash_entry *nhe) { /* Remove it from any lists it may be on */ zebra_nhg_depends_release(nhe); @@ -788,10 +876,17 @@ static void zebra_nhg_release(struct nhg_hash_entry *nhe) if (nhe->ifp) if_nhg_dependents_del(nhe->ifp, nhe); - hash_release(zrouter.nhgs, nhe); - hash_release(zrouter.nhgs_id, nhe); + /* + * If its a dup, we didn't store it here and have to be + * sure we don't clear one thats actually being used. + */ + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE)) + hash_release(zrouter.nhgs, nhe); +} - zebra_nhg_free(nhe); +static void zebra_nhg_release_id(struct nhg_hash_entry *nhe) +{ + hash_release(zrouter.nhgs_id, nhe); } void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) @@ -801,7 +896,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) if (!zebra_nhg_depends_is_empty(nhe)) nhg_connected_tree_decrement_ref(&nhe->nhg_depends); - if (!nhe->is_kernel_nh && nhe->refcnt <= 0) + if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) zebra_nhg_uninstall_kernel(nhe); } @@ -1417,6 +1512,15 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) return curr_active; } +static void zebra_nhg_re_attach_ref(struct route_entry *re, + struct nhg_hash_entry *new) +{ + re->ng = new->nhg; + re->nhe_id = new->id; + + zebra_nhg_increment_ref(new); +} + int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) { struct nhg_hash_entry *old = NULL; @@ -1430,13 +1534,13 @@ int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) if (re->nhe_id != new->id) { old = zebra_nhg_lookup_id(re->nhe_id); - re->ng = new->nhg; - re->nhe_id = new->id; + zebra_nhg_re_attach_ref(re, new); - zebra_nhg_increment_ref(new); if (old) zebra_nhg_decrement_ref(old); - } + } else if (!re->ng) + /* This is the first time it's being attached */ + zebra_nhg_re_attach_ref(re, new); done: return ret; @@ -1504,7 +1608,6 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { - nhe->is_kernel_nh = false; int ret = dplane_nexthop_add(nhe); switch (ret) { @@ -1524,8 +1627,18 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) } } +static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe) +{ + zlog_debug("Freeing nhe_id=%u", nhe->id); + zebra_nhg_release_id(nhe); + zebra_nhg_free(nhe); +} + void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) { + /* Release from the non-ID hash'd table so nothing tries to use it */ + zebra_nhg_release_no_id(nhe); + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { int ret = dplane_nexthop_delete(nhe); @@ -1541,11 +1654,11 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) break; case ZEBRA_DPLANE_REQUEST_SUCCESS: UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_release(nhe); + zebra_nhg_handle_uninstall(nhe); break; } } else - zebra_nhg_release(nhe); + zebra_nhg_handle_uninstall(nhe); } static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) @@ -1554,16 +1667,16 @@ static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) nhe = (struct nhg_hash_entry *)bucket->data; - if (nhe && !nhe->is_kernel_nh) + if (ZEBRA_NHG_CREATED(nhe)) zebra_nhg_uninstall_kernel(nhe); } -void zebra_nhg_cleanup_tables(void) +void zebra_nhg_cleanup_tables(struct hash *hash) { // TODO: These should only be uninstalled via route cleanup // path? return; - hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL); + hash_iterate(hash, zebra_nhg_uninstall_created, NULL); } void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) @@ -1592,7 +1705,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_DELETE: if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_release(nhe); + zebra_nhg_handle_uninstall(nhe); } else { flog_err( EC_ZEBRA_DP_DELETE_FAIL, @@ -1641,3 +1754,18 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) dplane_ctx_fini(&ctx); } +static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) +{ + struct nhg_hash_entry *nhe = NULL; + + nhe = (struct nhg_hash_entry *)bucket->data; + + /* If its being ref'd, just let it be uninstalled via a route removal */ + if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) + zebra_nhg_uninstall_kernel(nhe); +} + +void zebra_nhg_sweep_table(struct hash *hash) +{ + hash_iterate(hash, zebra_nhg_sweep_entry, NULL); +} diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index e06d415b28..1fdda276cb 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -45,7 +45,7 @@ struct nhg_hash_entry { uint32_t id; afi_t afi; vrf_id_t vrf_id; - bool is_kernel_nh; + int type; struct nexthop_group *nhg; @@ -77,24 +77,32 @@ struct nhg_hash_entry { * and correct( ie no recursive pointer ) or a nexthop that is recursively * resolved and correct. */ -#define NEXTHOP_GROUP_VALID 0x1 +#define NEXTHOP_GROUP_VALID (1 << 0) /* * Has this nexthop group been installed? At this point in time, this * means that the data-plane has been told about this nexthop group * and it's possible usage by a route entry. */ -#define NEXTHOP_GROUP_INSTALLED 0x2 +#define NEXTHOP_GROUP_INSTALLED (1 << 1) /* * Has the nexthop group been queued to be send to the FIB? * The NEXTHOP_GROUP_VALID flag should also be set by this point. */ -#define NEXTHOP_GROUP_QUEUED 0x4 +#define NEXTHOP_GROUP_QUEUED (1 << 2) /* * Is this a nexthop that is recursively resolved? */ -#define NEXTHOP_GROUP_RECURSIVE 0x8 +#define NEXTHOP_GROUP_RECURSIVE (1 << 3) +/* + * This is a duplicate nexthop we got from the kernel, we are only tracking + * it in our ID hash table, it is unusable by our routes. + */ +#define NEXTHOP_GROUP_DUPLICATE (1 << 4) }; +/* Was this one we created, either this session or previously? */ +#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG) + /* Abstraction for connected trees */ struct nhg_connected { struct nhg_connected_tree_item tree_item; @@ -135,7 +143,11 @@ struct nhg_ctx { vrf_id_t vrf_id; afi_t afi; - bool is_kernel_nh; + /* + * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel + * created nexthop not made by us. + */ + int type; /* If its a group array, how many? */ uint8_t count; @@ -216,7 +228,8 @@ extern int nhg_ctx_process(struct nhg_ctx *ctx); /* Find via kernel nh creation */ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, uint8_t count, - vrf_id_t vrf_id, afi_t afi); + vrf_id_t vrf_id, afi_t afi, int type, + int startup); /* Find via route creation */ extern struct nhg_hash_entry * @@ -242,9 +255,11 @@ extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); -void zebra_nhg_cleanup_tables(void); +void zebra_nhg_cleanup_tables(struct hash *hash); /* Forward ref of dplane update context type */ struct zebra_dplane_ctx; void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx); + +void zebra_nhg_sweep_table(struct hash *hash); #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c89033b18c..bc647864ff 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3374,6 +3374,7 @@ int rib_sweep_route(struct thread *t) } zebra_router_sweep_route(); + zebra_router_sweep_nhgs(); return 0; } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index b85319df73..d6ec6ac165 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -154,6 +154,11 @@ void zebra_router_sweep_route(void) } } +void zebra_router_sweep_nhgs(void) +{ + zebra_nhg_sweep_table(zrouter.nhgs_id); +} + static void zebra_router_free_table(struct zebra_router_table *zrt) { void *table_info; @@ -275,5 +280,5 @@ void zebra_router_init(void) */ void zebra_router_cleanup(void) { - zebra_nhg_cleanup_tables(); + zebra_nhg_cleanup_tables(zrouter.nhgs_id); } diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 497846e0fa..ac4c961475 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -160,6 +160,7 @@ extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, extern int zebra_router_config_write(struct vty *vty); extern void zebra_router_sweep_route(void); +extern void zebra_router_sweep_nhgs(void); extern void zebra_router_show_table_summary(struct vty *vty); -- cgit v1.2.3 From bc541126e4058b6139f6b693a1adc9af2332317d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 1 Aug 2019 17:36:56 -0400 Subject: zebra: Use nexthop object id on route delete When we receive a route delete from the kernel and it contains a nexthop object id, use that to match against route gateways with instead of explicit nexthops. Signed-off-by: Stephen Worley --- zebra/connected.c | 6 ++--- zebra/kernel_socket.c | 8 +++--- zebra/redistribute.c | 2 +- zebra/rib.h | 4 +-- zebra/rt_netlink.c | 75 ++++++++++++++++++++++++++++----------------------- zebra/zapi_msg.c | 2 +- zebra/zebra_rib.c | 9 ++++--- 7 files changed, 58 insertions(+), 48 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/connected.c b/zebra/connected.c index b69c5c6e71..e21b778e3e 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -393,11 +393,11 @@ void connected_down(struct interface *ifp, struct connected *ifc) * Same logic as for connected_up(): push the changes into the * head. */ - rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, zvrf->table_id, 0, 0, false); + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, + 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, zvrf->table_id, 0, 0, false); + 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 13dd9c8dc1..c2812aa47b 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1139,8 +1139,8 @@ void rtm_read(struct rt_msghdr *rtm) */ if (rtm->rtm_type == RTM_CHANGE) rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, - 0, zebra_flags, &p, NULL, NULL, RT_TABLE_MAIN, - 0, 0, true); + 0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0, + 0, true); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, @@ -1148,8 +1148,8 @@ void rtm_read(struct rt_msghdr *rtm) 0, 0, 0, 0); else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, - 0, zebra_flags, &p, NULL, &nh, RT_TABLE_MAIN, - 0, 0, true); + 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, + 0, true); } /* Interface function for the kernel routing table updates. Support diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 42f8c812b4..4e0163f8ac 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -696,7 +696,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, prefix_copy(&p, &rn->p); rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, - re->table, re->flags, &p, NULL, re->ng->nexthop, + re->table, re->flags, &p, NULL, re->ng->nexthop, re->nhe_id, zvrf->table_id, re->metric, re->distance, false); return 0; diff --git a/zebra/rib.h b/zebra/rib.h index 2652b12abf..35aa011c0d 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -373,8 +373,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, uint8_t distance, - bool fromkernel); + uint32_t nhe_id, 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 840354a8bc..cdd7b5a92a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -772,44 +772,51 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, XFREE(MTYPE_RE, re); } } else { - // TODO: Use nhe_id here as well - if (!tb[RTA_MULTIPATH]) { - struct nexthop nh; - size_t sz = (afi == AFI_IP) ? 4 : 16; - - memset(&nh, 0, sizeof(nh)); - if (bh_type == BLACKHOLE_UNSPEC) { - if (index && !gate) - nh.type = NEXTHOP_TYPE_IFINDEX; - else if (index && gate) - nh.type = - (afi == AFI_IP) - ? NEXTHOP_TYPE_IPV4_IFINDEX - : NEXTHOP_TYPE_IPV6_IFINDEX; - else if (!index && gate) - nh.type = (afi == AFI_IP) - ? NEXTHOP_TYPE_IPV4 - : NEXTHOP_TYPE_IPV6; - else { + if (nhe_id) { + rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, + &p, &src_p, NULL, nhe_id, table, metric, + distance, true); + } else { + if (!tb[RTA_MULTIPATH]) { + struct nexthop nh; + size_t sz = (afi == AFI_IP) ? 4 : 16; + + memset(&nh, 0, sizeof(nh)); + if (bh_type == BLACKHOLE_UNSPEC) { + if (index && !gate) + nh.type = NEXTHOP_TYPE_IFINDEX; + else if (index && gate) + nh.type = + (afi == AFI_IP) + ? NEXTHOP_TYPE_IPV4_IFINDEX + : NEXTHOP_TYPE_IPV6_IFINDEX; + else if (!index && gate) + nh.type = + (afi == AFI_IP) + ? NEXTHOP_TYPE_IPV4 + : NEXTHOP_TYPE_IPV6; + else { + nh.type = + NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = BLACKHOLE_UNSPEC; + } + } else { nh.type = NEXTHOP_TYPE_BLACKHOLE; - nh.bh_type = BLACKHOLE_UNSPEC; + nh.bh_type = bh_type; } + nh.ifindex = index; + if (gate) + memcpy(&nh.gate, gate, sz); + rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, + flags, &p, &src_p, &nh, 0, table, + metric, distance, true); } else { - nh.type = NEXTHOP_TYPE_BLACKHOLE; - nh.bh_type = bh_type; + /* 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, 0, table, + metric, distance, true); } - nh.ifindex = index; - if (gate) - memcpy(&nh.gate, gate, sz); - rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &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, distance, - true); } } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index ecbf39dda0..ab4c246d16 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1635,7 +1635,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) table_id = zvrf->table_id; rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance, - api.flags, &api.prefix, src_p, NULL, table_id, api.metric, + api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric, api.distance, false); /* Stats */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index bc647864ff..1440171584 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2854,8 +2854,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, uint8_t distance, - bool fromkernel) + uint32_t nhe_id, uint32_t table_id, uint32_t metric, + uint8_t distance, bool fromkernel) { struct route_table *table; struct route_node *rn; @@ -2926,7 +2926,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, break; } /* Make sure that the route found has the same gateway. */ - else { + else if (nhe_id && re->nhe_id == nhe_id) { + same = re; + break; + } else { if (nh == NULL) { same = re; break; -- cgit v1.2.3 From 9ef49038d59e388a442c265d03d27c4d5e9c7e27 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 7 Aug 2019 11:33:01 -0400 Subject: lib,zebra: Move nexthop dup marking into creation We were waiting until install time to mark nexthops as duplicate. Since they are immutable now and re-used, move this marking into when they are actually created to save a bunch of cycles. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 18 ++++++++++++++++++ lib/nexthop_group.h | 1 + zebra/zebra_nhg.c | 4 ++++ zebra/zebra_rib.c | 16 +--------------- 4 files changed, 24 insertions(+), 15 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index fb569360c4..8bb6fc9593 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -302,6 +302,24 @@ uint32_t nexthop_group_hash(const struct nexthop_group *nhg) return key; } +void nexthop_group_mark_duplicates(struct nexthop_group *nhg) +{ + struct nexthop *nexthop, *prev; + + for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE); + for (ALL_NEXTHOPS_PTR(nhg, prev)) { + if (prev == nexthop) + break; + if (nexthop_same_firsthop(nexthop, prev)) { + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE); + break; + } + } + } +} + static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc) { struct nexthop *nexthop; diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index a765b4b76b..291a259f93 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -50,6 +50,7 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg); uint32_t nexthop_group_hash(const struct nexthop_group *nhg); +void nexthop_group_mark_duplicates(struct nexthop_group *nhg); /* The following for loop allows to iterate over the nexthop * structure of routes. diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3a2efacd9b..9e19c8d0e3 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -346,6 +346,10 @@ static void *zebra_nhg_hash_alloc(void *arg) struct nhg_hash_entry *copy = arg; nhe = zebra_nhg_copy(copy, copy->id); + + /* Mark duplicate nexthops in a group at creation time. */ + nexthop_group_mark_duplicates(nhe->nhg); + zebra_nhg_connect_depends(nhe, copy->nhg_depends); zebra_nhg_insert_id(nhe); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1440171584..52cc019d7c 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -528,23 +528,9 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; - } else { - struct nexthop *prev; - - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE); - for (ALL_NEXTHOPS_PTR(re->ng, prev)) { - if (prev == nexthop) - break; - if (nexthop_same_firsthop(nexthop, prev)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_DUPLICATE); - break; - } - } - } } + /* * Install the resolved nexthop object first. */ -- cgit v1.2.3 From 986a6617cc9425dfa4f9fcc879a4d98a3ab00b7c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 7 Aug 2019 13:47:34 -0400 Subject: zebra: Optimize the fib/notified nexthop matching Optimize the fib and notified nexthop group comparison algorithm to assume ordering. There were some pretty serious performance hits with this on high ecmp routes. Signed-off-by: Stephen Worley --- lib/nexthop.c | 13 +++++++ lib/nexthop.h | 2 +- zebra/zebra_rib.c | 112 ++++++++++++++++-------------------------------------- 3 files changed, 47 insertions(+), 80 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/lib/nexthop.c b/lib/nexthop.c index da7c934efa..3ab7284492 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -364,6 +364,19 @@ struct nexthop *nexthop_next(struct nexthop *nexthop) return NULL; } +/* Return the next nexthop in the tree that is resolved and active */ +struct nexthop *nexthop_next_active_resolved(struct nexthop *nexthop) +{ + struct nexthop *next = nexthop_next(nexthop); + + while (next + && (CHECK_FLAG(next->flags, NEXTHOP_FLAG_RECURSIVE) + || !CHECK_FLAG(next->flags, NEXTHOP_FLAG_ACTIVE))) + next = nexthop_next(next); + + return next; +} + unsigned int nexthop_level(struct nexthop *nexthop) { unsigned int rv = 0; diff --git a/lib/nexthop.h b/lib/nexthop.h index 5558e857f6..dfb30a1bce 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -154,7 +154,7 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2); extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size); extern struct nexthop *nexthop_next(struct nexthop *nexthop); -extern struct nexthop *nexthop_recursive_next(struct nexthop *nexthop); +extern struct nexthop *nexthop_next_active_resolved(struct nexthop *nexthop); extern unsigned int nexthop_level(struct nexthop *nexthop); /* Copies to an already allocated nexthop struct */ extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 52cc019d7c..d4abb61f22 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1421,76 +1421,20 @@ static bool rib_update_re_from_ctx(struct route_entry *re, * status. */ - /* - * First check the fib nexthop-group, if it's present. The comparison - * here is quite strict: we require that the fib sets match exactly. + /* Check both fib group and notif group for equivalence. + * + * Let's assume the nexthops are ordered here to save time. */ - matched = false; - do { - if (re->fib_ng.nexthop == NULL) - break; - - matched = true; - - /* First check the route's fib nexthops */ - for (ALL_NEXTHOPS(re->fib_ng, nexthop)) { - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - ctx_nexthop = NULL; - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), - ctx_nexthop)) { - if (nexthop_same(ctx_nexthop, nexthop)) - break; - } - - if (ctx_nexthop == NULL) { - /* Nexthop not in the new installed set */ - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - nexthop2str(nexthop, nh_str, - sizeof(nh_str)); - zlog_debug("update_from_ctx: no match for fib nh %s", - nh_str); - } - - matched = false; - break; - } - } - - if (!matched) - break; - - /* Check the new installed set */ - ctx_nexthop = NULL; - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) { - - if (CHECK_FLAG(ctx_nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) - continue; - - /* Compare with the current group's nexthops */ - nexthop = NULL; - for (ALL_NEXTHOPS(re->fib_ng, nexthop)) { - if (nexthop_same(nexthop, ctx_nexthop)) - break; - } - - if (nexthop == NULL) { - /* Nexthop not in the old installed set */ - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - nexthop2str(ctx_nexthop, nh_str, - sizeof(nh_str)); - zlog_debug("update_from_ctx: no fib match for notif nh %s", - nh_str); - } - matched = false; - break; - } + if (nexthop_group_equal(&re->fib_ng, dplane_ctx_get_ng(ctx)) == false) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + zlog_debug( + "%u:%s update_from_ctx: notif nh and fib nh mismatch", + re->vrf_id, dest_str); } - } while (0); + matched = false; + } else + matched = true; /* If the new FIB set matches the existing FIB set, we're done. */ if (matched) { @@ -1523,8 +1467,21 @@ static bool rib_update_re_from_ctx(struct route_entry *re, * walk the RIB group, looking for the 'installable' candidate * nexthops, and then check those against the set * that is actually installed. + * + * Assume nexthops are ordered here as well. */ matched = true; + + ctx_nexthop = dplane_ctx_get_ng(ctx)->nexthop; + + /* Get the first `installed` one to check against. + * If the dataplane doesn't set these to be what was actually installed, + * it will just be whatever was in re->ng? + */ + if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE) + || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop); + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -1534,20 +1491,15 @@ static bool rib_update_re_from_ctx(struct route_entry *re, continue; /* Check for a FIB nexthop corresponding to the RIB nexthop */ - ctx_nexthop = NULL; - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) { - if (nexthop_same(ctx_nexthop, nexthop)) - break; - } - - /* If the FIB doesn't know about the nexthop, - * it's not installed - */ - if (ctx_nexthop == NULL) { + if (nexthop_same(ctx_nexthop, nexthop) == false) { + /* If the FIB doesn't know about the nexthop, + * it's not installed + */ if (IS_ZEBRA_DEBUG_RIB_DETAILED) { nexthop2str(nexthop, nh_str, sizeof(nh_str)); - zlog_debug("update_from_ctx: no notif match for rib nh %s", - nh_str); + zlog_debug( + "update_from_ctx: no notif match for rib nh %s", + nh_str); } matched = false; @@ -1571,6 +1523,8 @@ static bool rib_update_re_from_ctx(struct route_entry *re, UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } + + ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop); } /* If all nexthops were processed, we're done */ -- cgit v1.2.3 From fec211ad95a3a2967e72d49ab3036ae01e4b3762 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 16:12:06 -0400 Subject: zebra: Zebra nexthop group re-work checkpatch fixes Checkpatch fixes for the zebra nexthop group re-work. Signed-off-by: Stephen Worley --- zebra/interface.c | 4 ++-- zebra/rt_netlink.c | 7 +++---- zebra/zebra_mpls.c | 2 +- zebra/zebra_nhg.c | 33 +++++++++++++++++---------------- zebra/zebra_rib.c | 31 +++++++++++++++++-------------- zebra/zebra_vty.c | 18 +++++++++--------- 6 files changed, 49 insertions(+), 46 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/interface.c b/zebra/interface.c index 4754762b97..76d5d2a246 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -195,7 +195,7 @@ static void if_nhg_dependents_release(struct interface *ifp) struct nhg_connected *rb_node_dep = NULL; struct zebra_if *zif = (struct zebra_if *)ifp->info; - frr_each (nhg_connected_tree, &zif->nhg_dependents, + frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) { rb_node_dep->nhe->ifp = NULL; zebra_nhg_set_invalid(rb_node_dep->nhe); @@ -1004,7 +1004,7 @@ static void if_down_nhg_dependents(const struct interface *ifp) struct nhg_connected *rb_node_dep = NULL; struct zebra_if *zif = (struct zebra_if *)ifp->info; - frr_each (nhg_connected_tree, &zif->nhg_dependents, + frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) { zebra_nhg_set_invalid(rb_node_dep->nhe); } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f626705085..c24745cf1c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -75,7 +75,7 @@ static vlanid_t filter_vlan = 0; -static bool supports_nh = false; +static bool supports_nh; struct gw_family_t { uint16_t filler; @@ -1974,7 +1974,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; req.nhm.nh_family = AF_UNSPEC; - // TODO: Scope? + /* TODO: Scope? */ uint32_t id = dplane_ctx_get_nhe_id(ctx); @@ -2139,7 +2139,6 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) "Context received for kernel nexthop update with incorrect OP code (%u)", dplane_ctx_get_op(ctx)); return ZEBRA_DPLANE_REQUEST_FAILURE; - break; } ret = netlink_nexthop(cmd, ctx); @@ -2548,7 +2547,7 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, req.n.nlmsg_type = cmd; req.ndm.ndm_family = PF_BRIDGE; req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT; - req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" + req.ndm.ndm_flags |= NTF_SELF; /* Handle by "self", not "master" */ addattr_l(&req.n, sizeof(req), diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 42d8c70f49..331ca44c67 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2669,7 +2669,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, nexthops_free(new_grp.nexthop); - return (found ? 0 : -1); + return found ? 0 : -1; } int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 8fb4f3357b..720c09397f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -80,7 +80,7 @@ void nhg_connected_tree_free(struct nhg_connected_tree_head *head) struct nhg_connected *rb_node_dep = NULL; if (!nhg_connected_tree_is_empty(head)) { - frr_each_safe (nhg_connected_tree, head, rb_node_dep) { + frr_each_safe(nhg_connected_tree, head, rb_node_dep) { nhg_connected_tree_del(head, rb_node_dep); nhg_connected_free(rb_node_dep); } @@ -89,7 +89,7 @@ void nhg_connected_tree_free(struct nhg_connected_tree_head *head) bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head) { - return (nhg_connected_tree_count(head) ? false : true); + return nhg_connected_tree_count(head) ? false : true; } struct nhg_connected * @@ -130,7 +130,7 @@ nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head) { struct nhg_connected *rb_node_dep = NULL; - frr_each_safe (nhg_connected_tree, head, rb_node_dep) { + frr_each_safe(nhg_connected_tree, head, rb_node_dep) { zebra_nhg_decrement_ref(rb_node_dep->nhe); } } @@ -140,7 +140,7 @@ nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head) { struct nhg_connected *rb_node_dep = NULL; - frr_each (nhg_connected_tree, head, rb_node_dep) { + frr_each(nhg_connected_tree, head, rb_node_dep) { zebra_nhg_increment_ref(rb_node_dep->nhe); } } @@ -209,7 +209,7 @@ static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe) if (!zebra_nhg_depends_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; - frr_each_safe (nhg_connected_tree, &nhe->nhg_depends, + frr_each_safe(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { zebra_nhg_dependents_del(rb_node_dep->nhe, nhe); } @@ -249,7 +249,7 @@ static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe) if (!zebra_nhg_dependents_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; - frr_each_safe (nhg_connected_tree, &nhe->nhg_dependents, + frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { zebra_nhg_depends_del(rb_node_dep->nhe, nhe); } @@ -295,7 +295,7 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, /* Attach backpointer to anything that it depends on */ zebra_nhg_dependents_init(nhe); if (!zebra_nhg_depends_is_empty(nhe)) { - frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { zebra_nhg_dependents_add(rb_node_dep->nhe, nhe); } } @@ -667,7 +667,7 @@ static bool zebra_nhg_contains_dup(struct nhg_hash_entry *nhe) { struct nhg_connected *rb_node_dep = NULL; - frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_DUPLICATE)) return true; @@ -770,7 +770,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) nhg_ctx_get_grp(ctx), count)) { depends_decrement_free(&nhg_depends); nexthop_group_free_delete(&nhg); - return ENOENT; + return -ENOENT; } if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type, @@ -891,7 +891,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx) switch (nhg_ctx_get_op(ctx)) { case NHG_CTX_OP_NEW: ret = nhg_ctx_process_new(ctx); - if (nhg_ctx_get_count(ctx) && ret == ENOENT + if (nhg_ctx_get_count(ctx) && ret == -ENOENT && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) { /* Depends probably came before group, re-queue. * @@ -1093,7 +1093,7 @@ void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) struct nhg_connected *rb_node_dep = NULL; /* If anthing else in the group is valid, the group is valid */ - frr_each (nhg_connected_tree, &nhe->nhg_dependents, + frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) @@ -1108,7 +1108,7 @@ void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) if (!zebra_nhg_dependents_is_empty(nhe)) { struct nhg_connected *rb_node_dep = NULL; - frr_each (nhg_connected_tree, &nhe->nhg_dependents, + frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { zebra_nhg_set_invalid(rb_node_dep->nhe); } @@ -1732,7 +1732,7 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, struct nhg_hash_entry *depend = NULL; uint8_t i = 0; - frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { bool duplicate = false; depend = rb_node_dep->nhe; @@ -1780,7 +1780,7 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) nhe = zebra_nhg_resolve(nhe); /* Make sure all depends are installed/queued */ - frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { zebra_nhg_install_kernel(rb_node_dep->nhe); } @@ -1846,8 +1846,9 @@ static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) void zebra_nhg_cleanup_tables(struct hash *hash) { - // TODO: These should only be uninstalled via route cleanup - // path? + /* + * TODO: These should only be uninstalled via route cleanup path? + */ return; hash_iterate(hash, zebra_nhg_uninstall_created, NULL); } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d4abb61f22..337a2f09c5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2865,27 +2865,30 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, same = re; break; } + /* Make sure that the route found has the same gateway. */ - else if (nhe_id && re->nhe_id == nhe_id) { + if (nhe_id && re->nhe_id == nhe_id) { same = re; break; - } else { - if (nh == NULL) { + } + + if (nh == NULL) { + same = re; + break; + } + for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) { + /* + * No guarantee all kernel send nh with labels + * on delete. + */ + if (nexthop_same_no_labels(rtnh, nh)) { same = re; break; } - for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) - /* - * No guarantee all kernel send nh with labels - * on delete. - */ - if (nexthop_same_no_labels(rtnh, nh)) { - same = re; - break; - } - if (same) - break; } + + if (same) + break; } /* If same type of route can't be found and this message is from kernel. */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e12d16333f..7f569cdb0e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1122,9 +1122,9 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) else vty_out(vty, " VRF: UNKNOWN\n"); - if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE)) { + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE)) vty_out(vty, " Duplicate - from kernel not hashable\n"); - } + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { vty_out(vty, " Valid"); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) @@ -1136,7 +1136,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) if (!zebra_nhg_depends_is_empty(nhe)) { vty_out(vty, " Depends:"); - frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); } vty_out(vty, "\n"); @@ -1162,7 +1162,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) case NEXTHOP_TYPE_IPV6_IFINDEX: vty_out(vty, " %s", inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, - sizeof buf)); + sizeof(buf))); if (nexthop->ifindex) vty_out(vty, ", %s", ifindex2ifname(nexthop->ifindex, @@ -1215,7 +1215,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) case NEXTHOP_TYPE_IPV4_IFINDEX: if (nexthop->src.ipv4.s_addr) { if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, - sizeof buf)) + sizeof(buf))) vty_out(vty, ", src %s", buf); } break; @@ -1223,7 +1223,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) case NEXTHOP_TYPE_IPV6_IFINDEX: if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, - sizeof buf)) + sizeof(buf))) vty_out(vty, ", src %s", buf); } break; @@ -1236,7 +1236,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) vty_out(vty, ", label %s", mpls_label2str(nexthop->nh_label->num_labels, nexthop->nh_label->label, buf, - sizeof buf, 1)); + sizeof(buf), 1)); } vty_out(vty, "\n"); @@ -1244,7 +1244,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) if (!zebra_nhg_dependents_is_empty(nhe)) { vty_out(vty, " Dependents:"); - frr_each (nhg_connected_tree, &nhe->nhg_dependents, + frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); } @@ -1299,7 +1299,7 @@ static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp) if (!if_nhg_dependents_is_empty(ifp)) { vty_out(vty, "Interface %s:\n", ifp->name); - frr_each (nhg_connected_tree, &zebra_if->nhg_dependents, + frr_each(nhg_connected_tree, &zebra_if->nhg_dependents, rb_node_dep) { vty_out(vty, " "); show_nexthop_group_out(vty, rb_node_dep->nhe); -- cgit v1.2.3 From d3a35138115f89c19d0c44776da705b52975909f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 14:04:43 -0400 Subject: lib,pbrd,zebra: Use one api to delete nexthops/group Reduce the api for deleting nexthops and the containing group to just one call rather than having a special case and handling it separately. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 8 ++------ lib/nexthop_group.h | 1 - pbrd/pbr_nht.c | 2 -- zebra/zapi_msg.c | 2 -- zebra/zebra_nhg.c | 6 +++--- zebra/zebra_rib.c | 6 +++--- zebra/zebra_rnh.c | 1 - 7 files changed, 8 insertions(+), 18 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 7d8bcd1166..9552f89568 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -212,15 +212,11 @@ void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from) } void nexthop_group_delete(struct nexthop_group **nhg) -{ - XFREE(MTYPE_NEXTHOP_GROUP, *nhg); -} - -void nexthop_group_free_delete(struct nexthop_group **nhg) { if ((*nhg)->nexthop) nexthops_free((*nhg)->nexthop); - nexthop_group_delete(nhg); + + XFREE(MTYPE_NEXTHOP_GROUP, *nhg); } /* Add nexthop to the end of a nexthop list. */ diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 378b0ce6bb..391775c69c 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -41,7 +41,6 @@ struct nexthop_group { struct nexthop_group *nexthop_group_new(void); void nexthop_group_delete(struct nexthop_group **nhg); -void nexthop_group_free_delete(struct nexthop_group **nhg); void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from); diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 062cfd0158..7ccd14d1f1 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -578,8 +578,6 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) hash_release(pbr_nhg_hash, pnhgc); - _nexthop_del(pbrms->nhg, nh); - nexthop_free(nh); nexthop_group_delete(&pbrms->nhg); XFREE(MTYPE_TMP, pbrms->internal_nhg_name); } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index ab4c246d16..d6ade783cf 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1537,7 +1537,6 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) EC_ZEBRA_NEXTHOP_CREATION_FAILED, "%s: Nexthops Specified: %d but we failed to properly create one", __PRETTY_FUNCTION__, api.nexthop_num); - nexthops_free(re->ng->nexthop); nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return; @@ -1580,7 +1579,6 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) flog_warn(EC_ZEBRA_RX_SRCDEST_WRONG_AFI, "%s: Received SRC Prefix but afi is not v6", __PRETTY_FUNCTION__); - nexthops_free(re->ng->nexthop); nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c22ed67f80..f4fc06efc9 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -769,7 +769,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) if (zebra_nhg_process_grp(nhg, &nhg_depends, nhg_ctx_get_grp(ctx), count)) { depends_decrement_free(&nhg_depends); - nexthop_group_free_delete(&nhg); + nexthop_group_delete(&nhg); return -ENOENT; } @@ -778,7 +778,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) depends_decrement_free(&nhg_depends); /* These got copied over in zebra_nhg_alloc() */ - nexthop_group_free_delete(&nhg); + nexthop_group_delete(&nhg); } else nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi, type); @@ -1046,7 +1046,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { - nexthop_group_free_delete(&nhe->nhg); + nexthop_group_delete(&nhe->nhg); /* Decrement to remove connection ref */ nhg_connected_tree_decrement_ref(&nhe->nhg_depends); nhg_connected_tree_free(&nhe->nhg_depends); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 337a2f09c5..e0bf1a58f2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2431,7 +2431,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (nhe) zebra_nhg_decrement_ref(nhe); } else if (re->ng) - nexthop_group_free_delete(&re->ng); + nexthop_group_delete(&re->ng); nexthops_free(re->fib_ng.nexthop); @@ -2667,7 +2667,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { if (re->ng) - nexthop_group_free_delete(&re->ng); + nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return 0; } @@ -2690,7 +2690,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, * The nexthops got copied over into an nhe, * so free them now. */ - nexthop_group_free_delete(&re->ng); + nexthop_group_delete(&re->ng); if (!nhe) { char buf[PREFIX_STRLEN] = ""; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index af3c1b818f..60e23cc4d4 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -940,7 +940,6 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, return; /* free RE and nexthops */ - nexthops_free(re->ng->nexthop); nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); } -- cgit v1.2.3