From 69171da26264826c8875e402cbe6093d5e944b4f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 24 Jan 2019 08:06:34 -0500 Subject: [PATCH 001/189] zebra: Add hash of nexthop groups This commit does nothing more than just create a hash structure that we will use to track nexthop groups. Signed-off-by: Donald Sharp --- zebra/zebra_nhg.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_nhg.h | 19 +++++++++++ zebra/zebra_router.c | 4 +++ zebra/zebra_router.h | 5 +++ 4 files changed, 109 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4e696b39ac14..b3fc46a66f28 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -26,6 +26,7 @@ #include "lib/nexthop_group_private.h" #include "lib/routemap.h" #include "lib/mpls.h" +#include "lib/jhash.h" #include "zebra/connected.h" #include "zebra/debug.h" @@ -558,3 +559,83 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) return re->nexthop_active_num; } +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_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; + int key = 0x5a351234; + + key = jhash_2words(nhe->vrf_id, nhe->afi, key); + + return jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); +} + +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; + + 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++; + } + + return true; +} + diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index ff2351c7599e..58f8e18b739c 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -24,6 +24,25 @@ #define __ZEBRA_NHG_H__ #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 { + afi_t afi; + vrf_id_t vrf_id; + + struct nexthop_group nhg; + + uint32_t refcnt; + uint32_t dplane_ref; +}; + +void zebra_nhg_init(void); +void zebra_nhg_terminate(void); + +extern uint32_t zebra_nhg_hash_key(const void *arg); + +extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); + #endif diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 1e9f9e4ec7d2..ffffa8c0014e 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -253,4 +253,8 @@ void zebra_router_init(void) zrouter.iptable_hash = hash_create_size(8, zebra_pbr_iptable_hash_key, zebra_pbr_iptable_hash_equal, "IPtable Hash Entry"); + + zrouter.nhgs = + hash_create_size(8, zebra_nhg_hash_key, zebra_nhg_hash_equal, + "Zebra Router Nexthop Groups"); } diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 25a7adac11f7..4bae701d2f13 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -132,6 +132,11 @@ struct zebra_router { * Time for when we sweep the rib from old routes */ time_t startup_time; + + /* + * The hash of nexthop groups associated with this router + */ + struct hash *nhgs; }; #define GRACEFUL_RESTART_TIME 60 From 21be136402a696ee11f36dabdf6c73b8b41729c4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 23 Jan 2019 21:16:41 -0500 Subject: [PATCH 002/189] zebra: Add show command to dump nexthop-group information for Zebra Just a simple addition of a command to dump the nexthop group information. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 92f8dd1ecc5e..13a51ca831f4 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -52,6 +52,7 @@ #include "zebra/ipforward.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_pbr.h" +#include "zebra/zebra_nhg.h" extern int allow_delete; @@ -1101,6 +1102,78 @@ DEFUN (ip_nht_default_route, return CMD_SUCCESS; } +static void show_nexthop_group_cmd_helper(struct vty *vty, + struct zebra_vrf *zvrf, afi_t afi) +{ + struct list *list = hash_to_list(zrouter.nhgs); + struct nhg_hash_entry *nhe; + struct listnode *node; + + 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\n", nhe->dplane_ref, + nhe->refcnt, nhe->afi); + + for (ALL_NEXTHOPS(nhe->nhg, nhop)) { + vty_out(vty, " "); + nexthop_group_write_nexthop(vty, nhop); + } + } + + list_delete(&list); +} + +DEFPY (show_nexthop_group, + show_nexthop_group_cmd, + "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) { + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct zebra_vrf *zvrf; + + zvrf = vrf->info; + if (!zvrf) + continue; + + vty_out(vty, "VRF: %s\n", vrf->name); + show_nexthop_group_cmd_helper(vty, zvrf, afi); + } + + return CMD_SUCCESS; + } + + if (vrf_name) + zvrf = zebra_vrf_lookup_by_name(vrf_name); + else + zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME); + + if (!zvrf) { + vty_out(vty, "VRF %s specified does not exist", vrf_name); + return CMD_SUCCESS; + } + + show_nexthop_group_cmd_helper(vty, zvrf, afi); + + return CMD_SUCCESS; +} + DEFUN (no_ip_nht_default_route, no_ip_nht_default_route_cmd, "no ip nht resolve-via-default", @@ -3033,6 +3106,8 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &zebra_packet_process_cmd); install_element(CONFIG_NODE, &no_zebra_packet_process_cmd); + install_element(VIEW_NODE, &show_nexthop_group_cmd); + install_element(VIEW_NODE, &show_vrf_cmd); install_element(VIEW_NODE, &show_vrf_vni_cmd); install_element(VIEW_NODE, &show_route_cmd); From c8ee3cdb39e160e1f0e85b3db7619e09624d92a1 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 23 Jan 2019 21:32:49 -0500 Subject: [PATCH 003/189] zebra: Add some basic flags to the zebra nexthop group We need to track if a nexthop group is valid and installed, so create some basic flags to track this. Signed-off-by: Donald Sharp --- zebra/zebra_nhg.h | 15 +++++++++++++++ zebra/zebra_vty.c | 7 +++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 58f8e18b739c..ce3d2ed6c37f 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -36,6 +36,21 @@ struct nhg_hash_entry { uint32_t refcnt; uint32_t dplane_ref; + + uint32_t flags; +/* + * Is this nexthop group valid, ie all nexthops are fully resolved. + * What is fully resolved? It's a nexthop that is either self contained + * and correct( ie no recursive pointer ) or a nexthop that is recursively + * resolved and correct. + */ +#define NEXTHOP_GROUP_VALID 0x1 +/* + * 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 }; void zebra_nhg_init(void); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 13a51ca831f4..d9e8c6f96861 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1118,8 +1118,11 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, if (nhe->vrf_id != zvrf->vrf->vrf_id) continue; - vty_out(vty, "Group: %u RefCnt: %u afi: %d\n", nhe->dplane_ref, - nhe->refcnt, nhe->afi); + vty_out(vty, + "Group: %u RefCnt: %u afi: %d Valid: %d Installed: %d\n", + nhe->dplane_ref, nhe->refcnt, nhe->afi, + nhe->flags & NEXTHOP_GROUP_VALID, + nhe->flags & NEXTHOP_GROUP_INSTALLED); for (ALL_NEXTHOPS(nhe->nhg, nhop)) { vty_out(vty, " "); From 4e49c8b8a708e1ced07a1d18ae6b6554995c4085 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 24 Jan 2019 10:49:28 -0500 Subject: [PATCH 004/189] zebra: Add ability to find(create) and release a nhg from a re Add some code to allow us to do lookups and releases of nexthop groups from zebra. At this point we do not do anything with it. Signed-off-by: Donald Sharp --- zebra/zebra_nhg.c | 219 +++++++++++++++++++++++++++++----------------- zebra/zebra_nhg.h | 3 + 2 files changed, 141 insertions(+), 81 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index b3fc46a66f28..772227a46b5f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -36,6 +36,144 @@ #include "zebra/zebra_routemap.h" #include "zebra/rt.h" + +static void *zebra_nhg_alloc(void *arg) +{ + struct nhg_hash_entry *nhe; + struct nhg_hash_entry *copy = 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; + + nexthop_group_copy(&nhe->nhg, ©->nhg); + + nhe->refcnt = 1; + + 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_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; + int key = 0x5a351234; + + key = jhash_2words(nhe->vrf_id, nhe->afi, key); + + return jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); +} + +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; + + 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++; + } + + return true; +} + +void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, + struct route_entry *re) +{ + struct nhg_hash_entry lookup, *nhe; + + memset(&lookup, 0, sizeof(lookup)); + lookup.vrf_id = re->vrf_id; + lookup.afi = afi; + lookup.nhg = *nhg; + + nhe = hash_lookup(zrouter.nhgs, &lookup); + if (!nhe) + nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); + else + nhe->refcnt++; + + //re->ng = nhe->nhg; + + return; +} + +void zebra_nhg_release(afi_t afi, 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); + nhe->refcnt--; + + if (nhe->refcnt == 0) + hash_release(zrouter.nhgs, nhe); + // re->ng = NULL; +} + static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, struct nexthop *nexthop) { @@ -558,84 +696,3 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) return re->nexthop_active_num; } - -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_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; - int key = 0x5a351234; - - key = jhash_2words(nhe->vrf_id, nhe->afi, key); - - return jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); -} - -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; - - 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++; - } - - return true; -} - diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index ce3d2ed6c37f..2e538fe622ce 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -60,4 +60,7 @@ extern uint32_t zebra_nhg_hash_key(const void *arg); extern bool zebra_nhg_hash_equal(const void *arg1, const void *arg2); +extern void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, + struct route_entry *re); +void zebra_nhg_release(afi_t afi, struct route_entry *re); #endif From 22bcedb231390df39c327eba1f12f1da50da0bf2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 25 Jan 2019 20:11:21 -0500 Subject: [PATCH 005/189] 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(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c2fa33f57d78..f385a2d752e5 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); From ce0e6980179dabd9d056e147d6160c6dd22f2f44 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 12 Feb 2019 14:32:07 -0500 Subject: [PATCH 006/189] linux: Update our netlink headers for nexthop group support The linux kernel is adding support for nexthop groups. Update our includes to reflect new types and structs we should be listening for from the kernel. Signed-off-by: Stephen Worley --- include/linux/nexthop.h | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 include/linux/nexthop.h diff --git a/include/linux/nexthop.h b/include/linux/nexthop.h new file mode 100644 index 000000000000..e4d6e256ef0d --- /dev/null +++ b/include/linux/nexthop.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_NEXTHOP_H +#define _LINUX_NEXTHOP_H + +#include + +#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \ + NLMSG_ALIGN(sizeof(struct nhmsg)))) + +struct nhmsg { + unsigned char nh_family; + unsigned char nh_scope; /* return only */ + unsigned char nh_protocol; /* Routing protocol that installed nh */ + unsigned char resvd; + unsigned int nh_flags; /* RTNH_F flags */ +}; + +struct nexthop_grp { + __u32 id; /* nexthop id - must exist */ + __u8 weight; /* weight of this nexthop */ + __u8 resvd1; + __u16 resvd2; +}; + +enum { + NEXTHOP_GRP_TYPE_MPATH, /* default type if not specified */ + __NEXTHOP_GRP_TYPE_MAX, +}; + +#define NEXTHOP_GRP_TYPE_MAX (__NEXTHOP_GRP_TYPE_MAX - 1) + +enum { + NHA_UNSPEC, + NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */ + + NHA_GROUP, /* array of nexthop_grp */ + NHA_GROUP_TYPE, /* u16 one of NEXTHOP_GRP_TYPE */ + /* if NHA_GROUP attribute is added, no other attributes can be set */ + + NHA_BLACKHOLE, /* flag; nexthop used to blackhole packets */ + /* if NHA_BLACKHOLE is added, OIF, GATEWAY, ENCAP can not be set */ + + NHA_OIF, /* u32; nexthop device */ + NHA_GATEWAY, /* be32 (IPv4) or in6_addr (IPv6) gw address */ + NHA_ENCAP_TYPE, /* u16; lwt encap type */ + NHA_ENCAP, /* lwt encap data */ + + /* NHA_OIF can be appended to dump request to return only + * nexthops using given device + */ + NHA_GROUPS, /* flag; only return nexthop groups in dump */ + NHA_MASTER, /* u32; only return nexthops with given master dev */ + + __NHA_MAX, +}; + +#define NHA_MAX (__NHA_MAX - 1) +#endif From da0ad5cfc8485d67b88b6d37e9bdff3e404514c6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 7 Mar 2019 17:55:31 -0500 Subject: [PATCH 007/189] zebra: Add RTNLGRP_NEXTHOP group to the kernel socket Initialize the netlink socket with the RTNLGRP_NEXTHOP group as well to listen for. Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index f52b4746ae7f..615926b0de5f 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1096,7 +1096,8 @@ void kernel_init(struct zebra_ns *zns) RTMGRP_IPV4_MROUTE | RTMGRP_NEIGH | (1 << (RTNLGRP_IPV4_RULE - 1)) | - (1 << (RTNLGRP_IPV6_RULE - 1)); + (1 << (RTNLGRP_IPV6_RULE - 1)) | + (1 << (RTNLGRP_NEXTHOP - 1)); snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); From 79580b5ac4ba584baf2a50825949abff18c77f91 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 13 Feb 2019 15:32:59 -0500 Subject: [PATCH 008/189] zebra: Add base functionality for nexthop messages in kernel_netlink Add some base functionality so we can verify we are getting messages about nexthops from the kernel. Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 615926b0de5f..7889c70cff0e 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -99,6 +99,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_NEWRULE, "RTM_NEWRULE"}, {RTM_DELRULE, "RTM_DELRULE"}, {RTM_GETRULE, "RTM_GETRULE"}, + {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"}, + {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"}, + {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"}, {0}}; static const struct message rtproto_str[] = { @@ -291,6 +294,14 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return netlink_rule_change(h, ns_id, startup); case RTM_DELRULE: return netlink_rule_change(h, ns_id, startup); + case RTM_NEWNEXTHOP: + 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; default: /* * If we have received this message then From 6b46851168ef37eaacba28a2a655e15ae5934cd0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 13 Feb 2019 16:06:48 -0500 Subject: [PATCH 009/189] 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(-) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 0dc9de0c59fc..65b62679e8b9 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 ee1df89c0e07..455003c930f8 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 43e44cad166f..9bc919463ba5 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 e61e68b7fe2f..d207ee404689 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 bf343e06e501..31fcba083feb 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 f347d3955cf4..b54d8fbc1225 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 3054b8a34d20..a11517ab8b8c 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 8088ec1bfe2f..6e0c0b8d88de 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 772227a46b5f..407e29f8c322 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 09edbc9a68a6..3f1567a95b72 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 f385a2d752e5..c8ba3f9e9dbe 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 5df5d94f4b80..1494e3bed39b 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 d9e8c6f96861..32375e0a0091 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]++; From eecacedc3b9526b59ef690bce41f41158a137c9f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 15 Feb 2019 11:16:22 -0500 Subject: [PATCH 010/189] 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(-) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 65b62679e8b9..42f8c812b44d 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 455003c930f8..4bef6e054395 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 9bc919463ba5..b36fbb200810 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 c8ba3f9e9dbe..c56c953618cb 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 1494e3bed39b..af3c1b818f2f 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)) From 9a0d4dd39be7cbed048e45b5a27ceb81608d76f6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 15 Feb 2019 11:39:12 -0500 Subject: [PATCH 011/189] 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(-) diff --git a/zebra/rib.h b/zebra/rib.h index 4bef6e054395..5b5bd4c2793f 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 d207ee404689..ecbf39dda02f 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 e87fa0ad7118..debcf60ee5fb 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 407e29f8c322..569bc6e5eccc 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 c56c953618cb..d3c6f5ba113c 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; From 347bb8e26976758a3324c26c661479624eb09080 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 14 Feb 2019 17:42:25 -0500 Subject: [PATCH 012/189] zebra: Add error code for bad nhg messages from the kernel Needed an error code for nhg messages from the kernel. Signed-off-by: Stephen Worley --- zebra/zebra_errors.c | 9 +++++++++ zebra/zebra_errors.h | 1 + 2 files changed, 10 insertions(+) diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index a7e5147af3ca..65be47f4bc89 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -728,6 +728,15 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Check network topology to detect duplicate host IP for correctness.", }, + { + .code = EC_ZEBRA_BAD_NHG_MESSAGE, + .title = + "Bad Nexthop Group Message", + .description = + "Zebra received Nexthop Group message from the kernel that it cannot process.", + .suggestion = + "Check the kernel's link states and routing table to see how it matches ours." + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 222055dd81d7..f35c4659759b 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -125,6 +125,7 @@ enum zebra_log_refs { EC_ZEBRA_DUP_MAC_DETECTED, EC_ZEBRA_DUP_IP_INHERIT_DETECTED, EC_ZEBRA_DUP_IP_DETECTED, + EC_ZEBRA_BAD_NHG_MESSAGE, }; void zebra_error_init(void); From d2bec88a36effcff8d91375b325a944dad36b5e4 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 15 Feb 2019 12:28:56 -0500 Subject: [PATCH 013/189] zebra: Separate interface address lookup Separate interface lookup into its own function. We need to know interfaces for reading in nexthop information, but we need to know nexthops for reading in the interface addresses. We will read in nexthops between the two. Signed-off-by: Stephen Worley --- zebra/if_netlink.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index d42f68cbe813..b402cc496571 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -807,6 +807,23 @@ int interface_lookup_netlink(struct zebra_ns *zns) /* fixup linkages */ zebra_if_update_all_links(); + return 0; +} + +/** + * interface_addr_lookup_netlink() - Look up interface addresses + * + * @zns: Zebra netlink socket + * Return: Result status + */ +static int interface_addr_lookup_netlink(struct zebra_ns *zns) +{ + int ret; + struct zebra_dplane_info dp_info; + struct nlsock *netlink_cmd = &zns->netlink_cmd; + + /* Capture key info from ns struct */ + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); /* Get IPv4 address of the interfaces. */ ret = netlink_request_intf_addr(netlink_cmd, AF_INET, RTM_GETADDR, 0); @@ -1460,6 +1477,7 @@ int netlink_protodown(struct interface *ifp, bool down) void interface_list(struct zebra_ns *zns) { interface_lookup_netlink(zns); + interface_addr_lookup_netlink(zns); } #endif /* GNU_LINUX */ From a95b8020ca4383dd4a43c18588c004b5683a8566 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 15 Feb 2019 13:18:48 -0500 Subject: [PATCH 014/189] zebra: Add a second table for indexing by ID The messages we get from the kernel come with ids only for groups, so lets index with those as well. Also adding a helper function for lookup and get with the two different tables. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 57 +++++++++++++++++++++++++++++++++++++------- zebra/zebra_nhg.h | 4 ++++ zebra/zebra_router.c | 6 +++++ zebra/zebra_router.h | 1 + 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 569bc6e5eccc..47e1054cef40 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -102,6 +102,21 @@ uint32_t zebra_nhg_hash_key(const void *arg) return jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); } +uint32_t zebra_nhg_id_key(const void *arg) +{ + const struct nhg_hash_entry *nhe = 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; @@ -137,19 +152,21 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) return true; } -void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, - struct route_entry *re) +/** + * Helper function for lookup and get() + * since we are using two different tables. + * + * Avoiding code duplication hopefully. + */ +static void zebra_nhg_lookup_get(struct hash *hash_table, + struct nhg_hash_entry *lookup) { - struct nhg_hash_entry lookup, *nhe; + struct nhg_hash_entry *nhe; - memset(&lookup, 0, sizeof(lookup)); - lookup.vrf_id = re->vrf_id; - lookup.afi = afi; - lookup.nhg = *nhg; + nhe = hash_lookup(hash_table, lookup); - nhe = hash_lookup(zrouter.nhgs, &lookup); if (!nhe) - nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); + nhe = hash_get(hash_table, lookup, zebra_nhg_alloc); else nhe->refcnt++; @@ -158,6 +175,28 @@ void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, return; } +void zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) +{ + struct nhg_hash_entry lookup = {0}; + + lookup.nhg = *nhg; + + zebra_nhg_lookup_get(zrouter.nhgs_id, &lookup); +} + +void zebra_nhg_find(afi_t afi, 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; + + zebra_nhg_lookup_get(zrouter.nhgs, &lookup); +} + void zebra_nhg_release(afi_t afi, struct route_entry *re) { struct nhg_hash_entry lookup, *nhe; diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 2e538fe622ce..e93b579560c4 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -29,6 +29,7 @@ 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; @@ -57,10 +58,13 @@ void zebra_nhg_init(void); void zebra_nhg_terminate(void); 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 void zebra_nhg_find(afi_t afi, 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); #endif diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index ffffa8c0014e..100d17ecded8 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -254,7 +254,13 @@ 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, + "Zebra Router Nexthop Groups ID index"); } diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 4bae701d2f13..cdf8fbe9e8ba 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -137,6 +137,7 @@ struct zebra_router { * The hash of nexthop groups associated with this router */ struct hash *nhgs; + struct hash *nhgs_id; }; #define GRACEFUL_RESTART_TIME 60 From 3463f295e79bfc34e4e8164f4faabe2bb6d6ed2a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 22 Feb 2019 14:12:46 -0500 Subject: [PATCH 015/189] zebra: Add error codes for nhg table insert failures Since we are using two different tables to hash the next groups with, lets add an error message in case there is a failure to insert into one of them. This will help to notify if the tables are not synced. Signed-off-by: Stephen Worley --- zebra/zebra_errors.c | 9 +++++++++ zebra/zebra_errors.h | 1 + 2 files changed, 10 insertions(+) diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 65be47f4bc89..74eddf51d094 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -283,6 +283,15 @@ static struct log_ref ferr_zebra_err[] = { .description = "Zebra received an event from inotify, but failed to read what it was.", .suggestion = "Notify a developer.", }, + { + .code = EC_ZEBRA_NHG_TABLE_INSERT_FAILED, + .title = + "Nexthop Group Hash Table Insert Failure", + .description = + "Zebra failed in inserting a Nexthop Group into its hash tables.", + .suggestion = + "Check to see if the entry already exists or if the netlink message was parsed incorrectly." + }, /* Warnings */ { .code = EC_ZEBRAING_LM_PROTO_MISMATCH, diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index f35c4659759b..37e0a229193c 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -72,6 +72,7 @@ enum zebra_log_refs { EC_ZEBRA_VNI_DEL_FAILED, EC_ZEBRA_VTEP_ADD_FAILED, EC_ZEBRA_VNI_ADD_FAILED, + EC_ZEBRA_NHG_TABLE_INSERT_FAILED, /* warnings */ EC_ZEBRA_NS_NOTIFY_READ, EC_ZEBRAING_LM_PROTO_MISMATCH, From f0cb8e16f03b37af2f22fe73372fa511dd7104e4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 26 Feb 2019 08:16:11 -0500 Subject: [PATCH 016/189] zebra: Add a nhe pointer to the route entry Add a nexthop hash entry to the route_entry so that we can track the nhe with the route entry. Signed-off-by: Donald Sharp --- zebra/rib.h | 2 ++ zebra/zebra_nhg.c | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 5b5bd4c2793f..a95bcc0550ef 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -93,6 +93,8 @@ struct route_entry { /* Nexthop group from FIB (optional) */ struct nexthop_group fib_ng; + struct nhg_hash_entry *nhe; + /* Tag */ route_tag_t tag; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 47e1054cef40..1839133310ff 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -158,8 +158,9 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) * * Avoiding code duplication hopefully. */ -static void zebra_nhg_lookup_get(struct hash *hash_table, - struct nhg_hash_entry *lookup) +static struct nhg_hash_entry * +zebra_nhg_lookup_get(struct hash *hash_table, + struct nhg_hash_entry *lookup) { struct nhg_hash_entry *nhe; @@ -170,9 +171,7 @@ static void zebra_nhg_lookup_get(struct hash *hash_table, else nhe->refcnt++; - //re->ng = nhe->nhg; - - return; + return nhe; } void zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg) @@ -194,7 +193,7 @@ void zebra_nhg_find(afi_t afi, struct nexthop_group *nhg, lookup.afi = afi; lookup.nhg = *nhg; - zebra_nhg_lookup_get(zrouter.nhgs, &lookup); + re->nhe = zebra_nhg_lookup_get(zrouter.nhgs, &lookup); } void zebra_nhg_release(afi_t afi, struct route_entry *re) From b589493e70323b050c566f465ea3076d5a52b943 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 26 Feb 2019 08:43:49 -0500 Subject: [PATCH 017/189] zebra: Add beginnings of nexthop group work queue Add the basic infrastructure for a nexthop group work queue. This queue will be used to validate and then install the new nexthop group. The result from the kernel when a new nexthop group is installed will cause the route entries that depend on it to be installed. Signed-off-by: Donald Sharp --- zebra/zebra_router.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index cdf8fbe9e8ba..29f2efce7c0e 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -106,6 +106,11 @@ struct zebra_router { #define ZEBRA_RIB_PROCESS_RETRY_TIME 1 struct work_queue *ribq; + /* The nexthop group work queue */ +#define ZEBRA_NHG_PROCESS_HOLD_TIME 1 +#define ZEBRA_NHG_PROCESS_RETRY_TIME 10 + struct work_queue *nhgq; + /* Meta Queue Information */ struct meta_queue *mq; From 98fd05580ce702cae1dc403dfd45ae18a6df87cd Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 25 Feb 2019 13:58:32 -0500 Subject: [PATCH 018/189] zebra: Add error code for duplicate nexthops Add an error code that indicates we received a nexthop from the kernel that is identical to one it/we already have other than its ID. Signed-off-by: Stephen Worley --- zebra/zebra_errors.c | 9 +++++++++ zebra/zebra_errors.h | 1 + 2 files changed, 10 insertions(+) diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 74eddf51d094..e14f1ee58c37 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -746,6 +746,15 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Check the kernel's link states and routing table to see how it matches ours." }, + { + .code = EC_ZEBRA_DUPLICATE_NHG_MESSAGE, + .title = + "Duplicate Nexthop Group Message", + .description = + "Zebra received Nexthop Group message from the kernel that it is identical to one it/we already have but with a different ID.", + .suggestion = + "See if the nexthop you are trying to add is already present in the fib." + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 37e0a229193c..44d61fc9b0d5 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -127,6 +127,7 @@ enum zebra_log_refs { EC_ZEBRA_DUP_IP_INHERIT_DETECTED, EC_ZEBRA_DUP_IP_DETECTED, EC_ZEBRA_BAD_NHG_MESSAGE, + EC_ZEBRA_DUPLICATE_NHG_MESSAGE, }; void zebra_error_init(void); From 8b5bdc8bdfdb95d5e22ccb8733dbd35c84f3f79d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 25 Feb 2019 17:59:28 -0500 Subject: [PATCH 019/189] 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(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1839133310ff..172212c65268 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 e93b579560c4..227e87256d34 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 d3c6f5ba113c..c8684c1a9318 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 32375e0a0091..b0b888381c78 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; } From d9f5b2f50f53d625986dbd47cd12778c9f841f0c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 25 Feb 2019 18:18:07 -0500 Subject: [PATCH 020/189] 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(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index b402cc496571..52d91007b409 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 7889c70cff0e..a81788028e05 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 b36fbb200810..b30805b9820d 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 29e0152bb2c9..2b4b145149c8 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 e14f1ee58c37..4f97f3669f0a 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 44d61fc9b0d5..73bb53a7737a 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 172212c65268..89f6691dab0e 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 227e87256d34..126f342c5448 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 c8684c1a9318..3b3bf921bc80 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 100d17ecded8..408fc16dd16f 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"); } From d1285db253f65a7863d94714bd16925c0e8a52cf Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 4 Mar 2019 11:54:44 -0500 Subject: [PATCH 021/189] zebra: Add flags to nexthops received from the kernel Added the appropriate flags that need to be set when we receive a nexthop from the kernel. They should be marked as ACTIVE and that they are in the FIB. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b30805b9820d..465b422c52ad 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2125,6 +2125,10 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } + 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 (nhe) { From 1ba2db775fe962912b0a089f564ab68d642b0466 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 4 Mar 2019 11:25:42 -0500 Subject: [PATCH 022/189] zebra: Add an error code for NHG update failures We needed an error code that can be used when we fail to install a nexthop group into the kernel/fib. Signed-off-by: Stephen Worley --- zebra/zebra_errors.c | 9 +++++++++ zebra/zebra_errors.h | 1 + 2 files changed, 10 insertions(+) diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 4f97f3669f0a..3ca1bf397182 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -301,6 +301,15 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Check the current status of the kernels nexthop groups and compare it to Zebra's." }, + { + .code = EC_ZEBRA_NHG_FIB_UPDATE, + .title = + "Zebra failed updating the fib with Nexthop Group", + .description = + "Zebra was not able to successfully install a new nexthop group into the fib", + .suggestion = + "Check to see if the nexthop group on the route you tried to install is valid." + }, /* Warnings */ { .code = EC_ZEBRAING_LM_PROTO_MISMATCH, diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 73bb53a7737a..1411980ba55b 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -74,6 +74,7 @@ enum zebra_log_refs { EC_ZEBRA_VNI_ADD_FAILED, EC_ZEBRA_NHG_TABLE_INSERT_FAILED, EC_ZEBRA_NHG_SYNC, + EC_ZEBRA_NHG_FIB_UPDATE, /* warnings */ EC_ZEBRA_NS_NOTIFY_READ, EC_ZEBRAING_LM_PROTO_MISMATCH, From f820d0250869daea93718402dc337fd1fb4ce7f4 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 1 Mar 2019 17:17:00 -0500 Subject: [PATCH 023/189] zebra: Add base functionality for nexthop processing via the dataplane Add all the neccessary code to allow nexthops to be processed in separate dataplane contexts with the netlink dataplane kernel provider. Signed-off-by: Stephen Worley --- zebra/if_netlink.c | 2 + zebra/rt.h | 8 +- zebra/rt_netlink.c | 151 ++++++++++++++++++++++++++++++++++++ zebra/zebra_dplane.c | 178 +++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_dplane.h | 20 +++++ 5 files changed, 357 insertions(+), 2 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 52d91007b409..7096ce19a716 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1482,6 +1482,8 @@ void interface_list(struct zebra_ns *zns) * so we need to get the nexthop info * from the kernel before we can do that */ + // TODO: Mark a failure with boolean on dataplane provider to indicate + // it is a kenrel that doesn't support nh objects. netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); } diff --git a/zebra/rt.h b/zebra/rt.h index f311a6b9d3e4..4b9a3f83fece 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -40,13 +40,17 @@ extern "C" { #define RSYSTEM_ROUTE(type) \ ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT) + /* - * Update or delete a route, LSP, pseudowire, or vxlan MAC from the kernel, - * using info from a dataplane context. + * Update or delete a route, nexthop, LSP, pseudowire, or vxlan MAC from the + * kernel, using info from a dataplane context. */ extern enum zebra_dplane_result kernel_route_update( struct zebra_dplane_ctx *ctx); +extern enum zebra_dplane_result +kernel_nexthop_update(struct zebra_dplane_ctx *ctx); + extern enum zebra_dplane_result kernel_lsp_update( struct zebra_dplane_ctx *ctx); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 465b422c52ad..067fca5ee09d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1845,6 +1845,157 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) return suc; } +/** + * netlink_nexthop() - Nexthop change via the netlink interface + * + * @ctx: Dataplane ctx + * + * Return: Result status + */ +static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) +{ + int ret = 0; + + struct { + struct nlmsghdr n; + struct nhmsg nhm; + char buf[NL_PKT_BUF_SIZE]; + } req; + + 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; + + req.nhm.nh_family = AF_UNSPEC; + // 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"); + return -1; + } + + 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 prefix *src_p; + unsigned char family = 0; + + switch (nh->type) { + // TODO: Need AF for just index also + // just use source? + case NEXTHOP_TYPE_IFINDEX: + src_p = dplane_ctx_get_src(ctx); + family = PREFIX_FAMILY(src_p); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + family = AF_INET; + addattr_l(&req.n, sizeof(req), NHA_GATEWAY, + &nh->gate.ipv4, IPV4_MAX_BYTELEN); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + family = AF_INET6; + addattr_l(&req.n, sizeof(req), NHA_GATEWAY, + &nh->gate.ipv6, IPV6_MAX_BYTELEN); + break; + case NEXTHOP_TYPE_BLACKHOLE: + family = AF_UNSPEC; + addattr_l(&req.n, sizeof(req), NHA_BLACKHOLE, NULL, 0); + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + flog_err( + EC_ZEBRA_NHG_FIB_UPDATE, + "Context received for kernel nexthop update without an interface"); + return -1; + break; + } + + req.nhm.nh_family = family; + req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_type(ctx)); + + addattr32(&req.n, sizeof(req), NHA_OIF, nh->ifindex); + + // TODO: Handle Encap + + } else if (cmd != RTM_DELNEXTHOP) { + flog_err( + EC_ZEBRA_NHG_FIB_UPDATE, + "Nexthop group kernel update command (%d) does not exist", + cmd); + return -1; + } + + + if (ret) { + zlog_debug("Something failed with inserting nhg into kernel"); + } + + return netlink_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); +} + +/** + * kernel_nexthop_update() - Update/delete a nexthop from the kernel + * + * @ctx: Dataplane context + * + * Return: Dataplane result flag + */ +enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) +{ + int cmd, ret = 0; + + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_NH_DELETE: + cmd = RTM_DELNEXTHOP; + break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + cmd = RTM_NEWNEXTHOP; + break; + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + case DPLANE_OP_NONE: + flog_err( + EC_ZEBRA_NHG_FIB_UPDATE, + "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); + + return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS + : ZEBRA_DPLANE_REQUEST_FAILURE); +} + /* * Update or delete a prefix from the kernel, * using info from a dataplane context. diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 31fcba083feb..d53defea11e9 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -95,6 +95,10 @@ struct dplane_route_info { uint32_t zd_mtu; uint32_t zd_nexthop_mtu; + /* Nexthop hash entry */ + // TODO: Adjust the others as needed + struct nhg_hash_entry zd_nhe; + /* Nexthops */ struct nexthop_group zd_ng; @@ -321,6 +325,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_route_errors; _Atomic uint32_t dg_other_errors; + _Atomic uint32_t dg_nexthops_in; + _Atomic uint32_t dg_nexthop_errors; + _Atomic uint32_t dg_lsps_in; _Atomic uint32_t dg_lsp_errors; @@ -461,6 +468,13 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_NH_DELETE: { + nexthops_free((*pctx)->u.rinfo.zd_nhe.nhg.nexthop); + break; + } + case DPLANE_OP_LSP_INSTALL: case DPLANE_OP_LSP_UPDATE: case DPLANE_OP_LSP_DELETE: @@ -638,6 +652,17 @@ const char *dplane_op2str(enum dplane_op_e op) ret = "ROUTE_NOTIFY"; break; + /* Nexthop update */ + case DPLANE_OP_NH_INSTALL: + ret = "NH_INSTALL"; + break; + case DPLANE_OP_NH_UPDATE: + ret = "NH_UPDATE"; + break; + case DPLANE_OP_NH_DELETE: + ret = "NH_DELETE"; + break; + case DPLANE_OP_LSP_INSTALL: ret = "LSP_INSTALL"; break; @@ -1015,6 +1040,14 @@ const struct zebra_dplane_info *dplane_ctx_get_ns( return &(ctx->zd_ns_info); } +/* Accessors for nexthop information */ +const struct nhg_hash_entry * +dplane_ctx_get_nhe(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return &(ctx->u.rinfo.zd_nhe); +} + /* Accessors for LSP information */ mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx) @@ -1449,6 +1482,38 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, return ret; } +/** + * dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @nhe: Nexthop group hash entry + * + * Return: Result status + */ +static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct nhg_hash_entry *nhe) +{ + int ret = EINVAL; + + if (!ctx || !nhe) + goto done; + + ctx->zd_op = op; + 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); + + ret = AOK; + +done: + return ret; +} + /* * Capture information for an LSP update in a dplane context. */ @@ -1697,6 +1762,49 @@ dplane_route_update_internal(struct route_node *rn, return result; } +/** + * dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes + * + * @nhe: Nexthop group hash entry where the change occured + * @op: The operation to be enqued + * + * Return: Result of the change + */ +static enum zebra_dplane_result +dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret = EINVAL; + struct zebra_dplane_ctx *ctx = NULL; + + /* Obtain context block */ + ctx = dplane_ctx_alloc(); + if (!ctx) { + ret = ENOMEM; + goto done; + } + + ret = dplane_ctx_nexthop_init(ctx, op, nhe); + if (ret == AOK) { + ret = dplane_update_enqueue(ctx); + } +done: + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + } + + return result; +} + /* * Enqueue a route 'add' for the dataplane. */ @@ -1852,6 +1960,43 @@ dplane_route_notif_update(struct route_node *rn, return ret; } +/* + * Enqueue a nexthop add for the dataplane. + */ +enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe) +{ + enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; + + if (nhe) + ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_INSTALL); + return ret; +} + +/* + * Enqueue a nexthop update for the dataplane. + */ +enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe) +{ + enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; + + if (nhe) + ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_UPDATE); + return ret; +} + +/* + * Enqueue a nexthop removal for the dataplane. + */ +enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe) +{ + enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; + + if (nhe) + ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_DELETE); + + return ret; +} + /* * Enqueue LSP add for the dataplane. */ @@ -2873,6 +3018,33 @@ kernel_dplane_address_update(struct zebra_dplane_ctx *ctx) return res; } +/** + * kernel_dplane_nexthop_update() - Handler for kernel nexthop updates + * + * @ctx: Dataplane context + * + * Return: Dataplane result flag + */ +static enum zebra_dplane_result +kernel_dplane_nexthop_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result res; + + 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_op2str(dplane_ctx_get_op(ctx))); + } + + res = kernel_nexthop_update(ctx); + + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1, + memory_order_relaxed); + + return res; +} + /* * Handler for kernel-facing EVPN MAC address updates */ @@ -2967,6 +3139,12 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) res = kernel_dplane_route_update(ctx); break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_NH_DELETE: + res = kernel_dplane_nexthop_update(ctx); + break; + case DPLANE_OP_LSP_INSTALL: case DPLANE_OP_LSP_UPDATE: case DPLANE_OP_LSP_DELETE: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index be945632c1ec..6ca2a274c6cf 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -30,6 +30,7 @@ #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/zebra_mpls.h" +#include "zebra/zebra_nhg.h" #ifdef __cplusplus extern "C" { @@ -108,6 +109,11 @@ enum dplane_op_e { DPLANE_OP_ROUTE_DELETE, DPLANE_OP_ROUTE_NOTIFY, + /* Nexthop update */ + DPLANE_OP_NH_INSTALL, + DPLANE_OP_NH_UPDATE, + DPLANE_OP_NH_DELETE, + /* LSP update */ DPLANE_OP_LSP_INSTALL, DPLANE_OP_LSP_UPDATE, @@ -269,6 +275,10 @@ const struct nexthop_group *dplane_ctx_get_ng( 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); + /* Accessors for LSP information */ mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx, @@ -373,6 +383,16 @@ enum zebra_dplane_result dplane_route_notif_update( enum dplane_op_e op, struct zebra_dplane_ctx *ctx); + +/* Forward ref of nhg_hash_entry */ +struct nhg_hash_entry; +/* + * Enqueue a nexthop change operation for the dataplane. + */ +enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe); +enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe); +enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe); + /* * Enqueue LSP change operations for the dataplane. */ From e8968ccb2b0b6032b58a2e6a6bedea4766e3cd90 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 11:13:43 -0500 Subject: [PATCH 024/189] zebra: Add kernel debugging function for netlink nexthop messages We needed a kernel debugging function for netlink nexthop messages when people are debugging kernel zebra messages. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 067fca5ee09d..fd2054686e6c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1433,6 +1433,13 @@ static void _netlink_route_debug(int cmd, const struct prefix *p, } } +static void _netlink_nexthop_debug(int cmd, uint32_t id) +{ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("netlink_nexthop(): %s, id=%u", + nl_msg_type_to_str(cmd), id); +} + static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) { if (IS_ZEBRA_DEBUG_KERNEL) From 1909e63acf228bd7e25abaa235e91defa9cc0b63 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 13:35:31 -0500 Subject: [PATCH 025/189] zebra: Add namespace info to the nexthop dataplane ctx The nexthop dataplane context was not getting populated with namespace info for its netlink messages. Fixed this to do lookups the same way we do it with route contexts. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index d53defea11e9..f20242bfc2c4 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1495,6 +1495,9 @@ 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; + int ret = EINVAL; if (!ctx || !nhe) @@ -1508,6 +1511,14 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, ctx->u.rinfo.zd_nhe.nhg.nexthop = NULL; nexthop_group_copy(&(ctx->u.rinfo.zd_nhe.nhg), &nhe->nhg); + /* Extract ns info - can't use pointers to 'core' structs */ + zvrf = vrf_info_lookup(nhe->vrf_id); + zns = zvrf->zns; + + // TODO: Might not need to mark this as an update, since + // it probably won't require two messages + dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE)); + ret = AOK; done: From e1536fce85b765cdc55993fc1635e030f1952fe2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 13:42:05 -0500 Subject: [PATCH 026/189] zebra: Add debug statement for nexthop netlink messages Add the zebra kernel debug statement for nexthop messages so we can see them via vtysh. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index fd2054686e6c..cb29a99d6f0a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1861,8 +1861,6 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) */ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) { - int ret = 0; - struct { struct nlmsghdr n; struct nhmsg nhm; @@ -1944,10 +1942,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) return -1; } - - if (ret) { - zlog_debug("Something failed with inserting nhg into kernel"); - } + _netlink_nexthop_debug(cmd, nhe->id); return netlink_talk_info(netlink_talk_filter, &req.n, dplane_ctx_get_ns(ctx), 0); From 4f096395c15508bb8a8dfc268a2c6103d63988fb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 13:43:40 -0500 Subject: [PATCH 027/189] zebra: Use the dest prefix for determining nexthop family Device only nexthops still need an address family associated with them. Decided to get this from the destination prefix on it. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cb29a99d6f0a..8850c88030c3 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1874,6 +1874,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *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; + req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; req.nhm.nh_family = AF_UNSPEC; // TODO: Scope? @@ -1894,15 +1895,15 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) // TODO: IF not a group const struct nexthop_group nhg = nhe->nhg; const struct nexthop *nh = nhg.nexthop; - const struct prefix *src_p; + const struct prefix *dest_p; unsigned char family = 0; switch (nh->type) { // TODO: Need AF for just index also - // just use source? + // just use dest? case NEXTHOP_TYPE_IFINDEX: - src_p = dplane_ctx_get_src(ctx); - family = PREFIX_FAMILY(src_p); + dest_p = dplane_ctx_get_dest(ctx); + family = PREFIX_FAMILY(dest_p); break; case NEXTHOP_TYPE_IPV4_IFINDEX: family = AF_INET; From cc4e065073e430321aeb5c88e925ad9780cf671b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 14:08:13 -0500 Subject: [PATCH 028/189] zebra: Add kernel condition check to see if it supports nexthops Added a check on startup for determining if the kernel supports nexthop objects. It sets an appropriate bool on the zebra namespace struct. Signed-off-by: Stephen Worley --- zebra/if_netlink.c | 14 +++++++++++--- zebra/zebra_ns.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 7096ce19a716..8c2caed1b0e1 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1482,9 +1482,17 @@ void interface_list(struct zebra_ns *zns) * so we need to get the nexthop info * from the kernel before we can do that */ - // TODO: Mark a failure with boolean on dataplane provider to indicate - // it is a kenrel that doesn't support nh objects. - netlink_nexthop_read(zns); + + if (netlink_nexthop_read(zns)) { + /* If the nexthop read fails, assume the kernel + * cannot handle nexthop objects. + */ + zlog_debug("Nexthop objects disabled on this kernel"); + zns->supports_nh = false; + } else { + zns->supports_nh = true; + } + interface_addr_lookup_netlink(zns); } diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index dc79a83db0d8..11aa1b74c9f8 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -54,6 +54,7 @@ struct zebra_ns { struct nlsock netlink_cmd; /* command channel */ struct nlsock netlink_dplane; /* dataplane channel */ struct thread *t_netlink; + bool supports_nh; /* Does kernel support nexthop objects? */ #endif struct route_table *if_table; From 60e0eaee230ad2471bf444496241e17305156e45 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 14:10:08 -0500 Subject: [PATCH 029/189] zebra: Return proper status result We were ignoring the status result interger from the netlink request and message parsing and just returning 0. Fixed this to return the result of the last one. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 8850c88030c3..d1e2092d073f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2362,7 +2362,7 @@ int netlink_nexthop_read(struct zebra_ns *zns) return ret; ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd, &dp_info, 0, 1); - return 0; + return ret; } From 7f6077d06322b2ac0d6741c33e644c4c4ec8a95c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 14:56:04 -0500 Subject: [PATCH 030/189] zebra: Add a queued flag to nhg_hash_entry Added a NEXTHOP_GROUP_QUEUED flag to the nexthop group hash entry struct. This indicates when we have sent it to be installed to the kernel and are waiting for the dataplane provider to process it. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 126f342c5448..e8c0a4b34b5f 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -50,6 +50,11 @@ struct nhg_hash_entry { * and it's possible usage by a route entry. */ #define NEXTHOP_GROUP_INSTALLED 0x2 +/* + * 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 }; void zebra_nhg_init(void); From 5be96a2d3a81bea0391722e820c09759da86a0c0 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 14:58:57 -0500 Subject: [PATCH 031/189] zebra: Add function to install a nhe into the kernel Add a function for installing Nexthop Group hash entires into the kernel. It sends the entry to the dataplane and does any post-processing immediately after that. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 25 +++++++++++++++++++++++++ zebra/zebra_nhg.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 89f6691dab0e..c5e1bbf5c2cb 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -36,6 +36,7 @@ #include "zebra/zebra_routemap.h" #include "zebra/rt.h" #include "zebra_errors.h" +#include "zebra_dplane.h" /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table @@ -845,3 +846,27 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) return curr_active; } + +/** + * zebra_nhg_install_kernel() - Install Nexthop Group hash entry into kernel + * + * @nhe: Nexthop Group hash entry to install + */ +void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) +{ + int ret = dplane_nexthop_add(nhe); + switch (ret) { + case ZEBRA_DPLANE_REQUEST_QUEUED: + SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); + break; + case ZEBRA_DPLANE_REQUEST_FAILURE: + flog_err(EC_ZEBRA_DP_INSTALL_FAIL, + "Failed to install Nexthop ID (%u) into the kernel", + nhe->id); + break; + case ZEBRA_DPLANE_REQUEST_SUCCESS: + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + break; + } +} + diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index e8c0a4b34b5f..d5f9a89df211 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -78,4 +78,6 @@ 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); + +void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); #endif From 75f8505d2e63c95a927bca0194ee381930e35592 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 15:04:23 -0500 Subject: [PATCH 032/189] zebra: Force re-install nexthop if still referenced Added functionality so that when we receive a RTM_DELNEXTHOP for a nhg_hash_entry that is still being referenced by a route, we immediately push it back to the kernel. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 10 +++++++++- zebra/zebra_nhg.c | 6 ++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index d1e2092d073f..bd0ec7848606 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2309,7 +2309,15 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } // TODO: Run some active check on all route_entry's? - zebra_nhg_release(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, sending it back down", + nhe->id); + zebra_nhg_install_kernel(nhe); + } else { + zebra_nhg_release(nhe); + } } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c5e1bbf5c2cb..253859fbe083 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -290,13 +290,11 @@ void zebra_nhg_free(void *arg) */ void zebra_nhg_release(struct nhg_hash_entry *nhe) { - if (nhe->refcnt) { + 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", + "Releasing a nexthop group with ID (%u) that we are still using for a route", nhe->id); - // TODO: Re-send to kernel - } hash_release(zrouter.nhgs, nhe); hash_release(zrouter.nhgs_id, nhe); From 147bad16b96824a3e881650ff89196ddd988ab7f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 7 Mar 2019 18:11:57 -0500 Subject: [PATCH 033/189] zebra: Add functions for installing/uninstalling nexthops Add functions for sending a nexthop to be queued on the dataplane for install/uninstall into the kernel. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 59 ++++++++++++++++++++++++++++++++++++----------- zebra/zebra_nhg.h | 3 +++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 253859fbe083..e876a99b6929 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -852,19 +852,52 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) */ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) { - int ret = dplane_nexthop_add(nhe); - switch (ret) { - case ZEBRA_DPLANE_REQUEST_QUEUED: - SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); - break; - case ZEBRA_DPLANE_REQUEST_FAILURE: - flog_err(EC_ZEBRA_DP_INSTALL_FAIL, - "Failed to install Nexthop ID (%u) into the kernel", - nhe->id); - break; - case ZEBRA_DPLANE_REQUEST_SUCCESS: - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - break; + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { + nhe->is_kernel_nh = false; + int ret = dplane_nexthop_add(nhe); + switch (ret) { + case ZEBRA_DPLANE_REQUEST_QUEUED: + SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); + break; + case ZEBRA_DPLANE_REQUEST_FAILURE: + flog_err( + EC_ZEBRA_DP_INSTALL_FAIL, + "Failed to install Nexthop ID (%u) into the kernel", + nhe->id); + break; + case ZEBRA_DPLANE_REQUEST_SUCCESS: + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + break; + } + } +} + +/** + * zebra_nhg_uninstall_kernel() - Uninstall Nexthop Group hash entry into kernel + * + * @nhe: Nexthop Group hash entry to uninstall + */ +void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) +{ + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { + int ret = dplane_nexthop_delete(nhe); + switch (ret) { + case ZEBRA_DPLANE_REQUEST_QUEUED: + SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); + break; + case ZEBRA_DPLANE_REQUEST_FAILURE: + flog_err( + EC_ZEBRA_DP_DELETE_FAIL, + "Failed to uninstall Nexthop ID (%u) from the kernel", + nhe->id); + break; + case ZEBRA_DPLANE_REQUEST_SUCCESS: + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + break; + } + } +} + } } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index d5f9a89df211..8ecb9d0636d3 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -80,4 +80,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); 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); #endif From 5f3c9e520c71993ca65a9aaafd9db715eda0b2e5 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 7 Mar 2019 18:15:30 -0500 Subject: [PATCH 034/189] zebra: Add dataplane process result function for nexthops Add a function that can handle the results of a dataplane ctx status, dpending on the operation performed. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++- zebra/zebra_nhg.h | 4 +++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index e876a99b6929..2ac8678e1251 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -36,7 +36,6 @@ #include "zebra/zebra_routemap.h" #include "zebra/rt.h" #include "zebra_errors.h" -#include "zebra_dplane.h" /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table @@ -898,6 +897,82 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) } } +/** + * zebra_nhg_dplane_result() - Process dplane result + * + * @ctx: Dataplane context + */ +void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op; + enum zebra_dplane_result status; + uint32_t id = 0; + struct nhg_hash_entry *nhe = NULL; + + op = dplane_ctx_get_op(ctx); + status = dplane_ctx_get_status(ctx); + + id = dplane_ctx_get_nhe(ctx)->id; + nhe = zebra_nhg_lookup_id(id); + + if (nhe) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug( + "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", + ctx, dplane_op2str(op), nhe->id, + dplane_res2str(status)); + + switch (op) { + 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, + "Failed to uninstall Nexthop ID (%u) from the kernel", + nhe->id); + } + break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } else { + flog_err( + EC_ZEBRA_DP_INSTALL_FAIL, + "Failed to install Nexthop ID (%u) into the kernel", + nhe->id); + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); + break; + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + case DPLANE_OP_NONE: + break; + } + dplane_ctx_fini(&ctx); + + } else { + flog_err( + EC_ZEBRA_NHG_SYNC, + "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table", + dplane_op2str(op), id); } } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 8ecb9d0636d3..a7a97f5529a5 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -26,6 +26,8 @@ #include "zebra/rib.h" #include "lib/nexthop_group.h" +#include "zebra/zebra_dplane.h" + struct nhg_hash_entry { uint32_t id; vrf_id_t vrf_id; @@ -83,4 +85,6 @@ 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_dplane_result(struct zebra_dplane_ctx *ctx); #endif From 8e7663796904f12ab31320d8d5a056da158483fe Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:16:52 -0500 Subject: [PATCH 035/189] 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(-) diff --git a/zebra/rib.h b/zebra/rib.h index a95bcc0550ef..e6d6d8744723 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 3b3bf921bc80..5f942a7ecf7f 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); From 044e54d1eb4cbd009bd2ab267ab03d78c22c2bba Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:23:34 -0500 Subject: [PATCH 036/189] zebra: Set the INSTALLED flags on nexthop entries we receive Add SETs to the flags on nexthop entries to mark installed/uninstalled from the kernel. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index bd0ec7848606..98138d607b4c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2299,6 +2299,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } } + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } else if (h->nlmsg_type == RTM_DELNEXTHOP) { if (!nhe) { flog_warn( @@ -2308,6 +2310,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + // TODO: Run some active check on all route_entry's? if (nhe->refcnt) { flog_err( From 9865e1c393ff3c3828a6ff85231c1144e86e03b4 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:26:33 -0500 Subject: [PATCH 037/189] 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(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5f942a7ecf7f..1ea11640d739 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: From e25f64010ef853728de087ad873e018f34a98382 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:29:43 -0500 Subject: [PATCH 038/189] zebra: Uninstall nexthop when ref count hits zero When nexthop entry reference counts hit zero and we created them, uninstall them from the kernel. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2ac8678e1251..c663022caa70 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -313,7 +313,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) nhe->refcnt--; if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { - zebra_nhg_release(nhe); + zebra_nhg_uninstall_kernel(nhe); } // re->ng = NULL; From 3e0372d20e9880c135a8d7ab880cd4105c0222f1 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 8 Mar 2019 10:35:38 -0500 Subject: [PATCH 039/189] zebra: Uninstall nexthops on shutdown Add functionality to uninstall nexthops we created on shutdown. To account for this, I added in a function for zebra_router cleanup in a shutdown event. Signed-off-by: Stephen Worley --- zebra/main.c | 2 ++ zebra/zebra_nhg.c | 24 ++++++++++++++++++++++++ zebra/zebra_router.c | 11 +++++++++++ zebra/zebra_router.h | 1 + 4 files changed, 38 insertions(+) diff --git a/zebra/main.c b/zebra/main.c index f0225ac5e6b6..e57b84c8f6f7 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -165,6 +165,8 @@ static void sigint(void) } if (zrouter.lsp_process_q) work_queue_free_and_null(&zrouter.lsp_process_q); + + zebra_router_cleanup(); vrf_terminate(); ns_walk_func(zebra_ns_early_shutdown); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c663022caa70..ece1e1ccd58a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -897,6 +897,30 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) } } +/** + * zebra_nhg_uninstall_created() - Uninstall nexthops we created in the kernel + * + * @nhe: Nexthop group hash entry + */ +static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) +{ + struct nhg_hash_entry *nhe = NULL; + + nhe = (struct nhg_hash_entry *)bucket->data; + + if (nhe && !nhe->is_kernel_nh) + zebra_nhg_uninstall_kernel(nhe); +} + +/** + * zebra_nhg_cleanup_tables() - Iterate over our tables to uninstall nh's + * we created + */ +void zebra_nhg_cleanup_tables(void) +{ + hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL); +} + /** * zebra_nhg_dplane_result() - Process dplane result * diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 408fc16dd16f..b85319df735a 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -266,3 +266,14 @@ void zebra_router_init(void) hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal, "Zebra Router Nexthop Groups ID index"); } + +/** + * zebra_router_cleanup() - Perform any cleanup actions before termination + * + * Right now this is just being used to clear the nexthops we installed in + * the kernel on shutdown before the routes are cleaned via vrf_terminated(). + */ +void zebra_router_cleanup(void) +{ + zebra_nhg_cleanup_tables(); +} diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 29f2efce7c0e..5a2f0c9fa154 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -150,6 +150,7 @@ struct zebra_router { extern struct zebra_router zrouter; extern void zebra_router_init(void); +extern void zebra_router_cleanup(void); extern void zebra_router_terminate(void); extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, From fcc89a9cfc9fbff3eacc66bdf38ca9dd0f0664f6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 10:46:25 -0400 Subject: [PATCH 040/189] zebra: Parse in nexthop ID information from new routes Add parsing code for nexthop object ID's when we get a route. When we get a new route with the new kernel, it will come with a nexthop ID and the nexthop full info. We should just reference by ID if it exists and point to the nexthop hash entry that matches it. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 98138d607b4c..03d1ee424c97 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -342,6 +342,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, uint32_t mtu = 0; uint8_t distance = 0; route_tag_t tag = 0; + uint32_t nhe_id = 0; void *dest = NULL; void *gate = NULL; @@ -446,6 +447,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (tb[RTA_GATEWAY]) gate = RTA_DATA(tb[RTA_GATEWAY]); + if (tb[RTA_NH_ID]) + nhe_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]); + if (tb[RTA_PRIORITY]) metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]); From 77a44d94f8d75461dc98fa27a94c8802481ab13e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 10:52:33 -0400 Subject: [PATCH 041/189] zebra: Put unicast nexthop parsing into its own function Move the nexthop unicast parsing into its own function to improve code readability. It was getting a bit too indented. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 121 ++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 03d1ee424c97..a030356f38d2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -321,6 +321,63 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels) return num_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) +{ + struct interface *ifp = NULL; + struct nexthop nh = {0}; + mpls_label_t labels[MPLS_MAX_LABELS] = {0}; + int num_labels = 0; + + size_t sz = (afi == AFI_IP) ? 4 : 16; + + 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 = bh_type; + } + } else { + nh.type = NEXTHOP_TYPE_BLACKHOLE; + nh.bh_type = bh_type; + } + nh.ifindex = index; + if (prefsrc) + memcpy(&nh.src, prefsrc, sz); + if (gate) + memcpy(&nh.gate, gate, sz); + + if (index) { + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), index); + if (ifp) + nh_vrf_id = ifp->vrf_id; + } + nh.vrf_id = nh_vrf_id; + + 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 (rtm->rtm_flags & RTNH_F_ONLINK) + SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); + + if (num_labels) + nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); + + return nh; +} + /* Looking up routing table by netlink interface. */ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, int startup) @@ -350,10 +407,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, void *src = NULL; /* IPv6 srcdest source prefix */ enum blackhole_type bh_type = BLACKHOLE_UNSPEC; - /* MPLS labels */ - mpls_label_t labels[MPLS_MAX_LABELS] = {0}; - int num_labels = 0; - rtm = NLMSG_DATA(h); if (startup && h->nlmsg_type != RTM_NEWROUTE) @@ -557,60 +610,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, vrf_id_t nh_vrf_id = vrf_id; if (!tb[RTA_MULTIPATH]) { - struct nexthop nh; - size_t sz = (afi == AFI_IP) ? 4 : 16; - - memset(&nh, 0, sizeof(nh)); + struct nexthop nh = {0}; - 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 = bh_type; - } - } else { - nh.type = NEXTHOP_TYPE_BLACKHOLE; - nh.bh_type = bh_type; - } - nh.ifindex = index; - if (prefsrc) - memcpy(&nh.src, prefsrc, sz); - if (gate) - memcpy(&nh.gate, gate, sz); - - if (index) { - ifp = if_lookup_by_index_per_ns( - zebra_ns_lookup(ns_id), - index); - if (ifp) - nh_vrf_id = ifp->vrf_id; - } - nh.vrf_id = nh_vrf_id; - - 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 (!nhe_id) { + nh = parse_nexthop_unicast( + ns_id, rtm, tb, bh_type, index, prefsrc, + gate, afi, nh_vrf_id); } - - if (rtm->rtm_flags & RTNH_F_ONLINK) - SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); - - if (num_labels) - nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, - num_labels, labels); - rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, &nh, table, metric, mtu, distance, tag); } else { @@ -619,6 +625,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, 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]); From 8032b71737520f883abeb1e43476d88cd5a4c304 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 10:55:53 -0400 Subject: [PATCH 042/189] 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(-) diff --git a/zebra/connected.c b/zebra/connected.c index 87cf8c8f205e..b69c5c6e713c 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 f5aca2341dee..13dd9c8dc13d 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 e6d6d8744723..6b8097dd131e 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 a030356f38d2..2744e6da9a77 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 725bb63a0d35..3ba5d6ee7351 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 1ea11640d739..196d7f1218c3 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; From bbb322f292cccb0cb60008acb8b50c89b37a8a4a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 10:58:05 -0400 Subject: [PATCH 043/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2744e6da9a77..7b38dd8bede0 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 196d7f1218c3..df1f3df091aa 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. */ From 602fea614f8272c3fdd9ed7c8a490ad12575425e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 16:29:57 -0400 Subject: [PATCH 044/189] zebra: Add nexthop hash entry list to zebra interface info Add a nexthop hash entry list to the local zebra interface info for each interface. This will allow us to modify nexthops on link events. Signed-off-by: Stephen Worley --- zebra/interface.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ zebra/interface.h | 25 ++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/zebra/interface.c b/zebra/interface.c index ef03cf87f62c..6b77f3c871ea 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -53,6 +53,7 @@ #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 @@ -120,6 +121,10 @@ 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_ptm_if_init(zebra_if); ifp->ptm_enable = zebra_ptm_get_enable_state(); @@ -196,6 +201,8 @@ static int if_zebra_delete_hook(struct interface *ifp) list_delete(&rtadv->AdvDNSSLList); #endif /* HAVE_RTADV */ + list_delete(&zebra_if->nhe_connected); + XFREE(MTYPE_TMP, zebra_if->desc); THREAD_OFF(zebra_if->speed_update); @@ -925,6 +932,51 @@ 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) +{ + struct nhe_connected *if_nhec = NULL; + 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; + + /* Add connected nexthop to the interface */ + listnode_add(zif->nhe_connected, if_nhec); + return if_nhec; +} + +/** + * nhe_connected() - Allocate nhe connected structure + * + * Return: Allocated nhe_connected structure + */ +struct nhe_connected *nhe_connected_new(void) +{ + return XCALLOC(MTYPE_NHE_CONNECTED, sizeof(struct nhe_connected)); +} + +/** + * 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. */ void if_up(struct interface *ifp) { @@ -1132,6 +1184,19 @@ 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) +{ + /* Just outputing ID for now. */ + vty_out(vty, " (%u)", connected->nhe->id); +} + static const char *zebra_ziftype_2str(zebra_iftype_t zif_type) { switch (zif_type) { @@ -1279,6 +1344,7 @@ 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; @@ -1364,6 +1430,14 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) connected_dump_vty(vty, connected); } + if (listhead(zebra_if->nhe_connected)) { + 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); + vty_out(vty, "\n"); + } + vty_out(vty, " Interface Type %s\n", zebra_ziftype_2str(zebra_if->zif_type)); if (IS_ZEBRA_IF_BRIDGE(ifp)) { diff --git a/zebra/interface.h b/zebra/interface.h index e134b9b4236d..270cc868c0ae 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -27,6 +27,7 @@ #include "hook.h" #include "zebra/zebra_l2.h" +#include "zebra/zebra_nhg.h" #ifdef __cplusplus extern "C" { @@ -263,6 +264,15 @@ typedef enum { 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; +}; + /* `zebra' daemon local interface structure. */ struct zebra_if { /* Shutdown configuration. */ @@ -277,6 +287,15 @@ struct zebra_if { /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; + /* Nexthops pointed to it list */ + /** + * 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; + /* Information about up/down changes */ unsigned int up_count; char up_last[QUAGGA_TIMESTAMP_LEN]; @@ -424,6 +443,12 @@ 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); + extern void vrf_add_update(struct vrf *vrfp); #ifdef HAVE_PROC_NET_DEV From 8c0a24c14ed9d0ee504463de9d8b8be9da5b5628 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 16:31:44 -0400 Subject: [PATCH 045/189] zebra: Add new nexthops to the interface nexthop hash entry list When we get a new nexthop and find the interface associated with it, add this nexthop to the interface's zebra interface info nexthop hash entry list. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7b38dd8bede0..73260ee18be4 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2096,17 +2096,18 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * * @tb: Netlink RTA data * @family: Address family in the nhmsg + * @ifp: Interface connected - this should be NULL, we fill it in * @ns_id: Namspace id * * Return: New nexthop */ 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}; void *gate = NULL; - struct interface *ifp = NULL; int if_index; size_t sz; @@ -2138,9 +2139,9 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, nh.ifindex = if_index; - ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex); + *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, @@ -2223,6 +2224,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* nexthop group id */ uint32_t id; unsigned char family; + struct interface *ifp = NULL; struct nhmsg *nhm = NULL; /* struct for nexthop group abstraction */ struct nexthop_group nhg = {0}; @@ -2290,7 +2292,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) * 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); + nh = netlink_nexthop_process_nh(tb, family, &ifp, + ns_id); } @@ -2310,6 +2313,12 @@ 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; } From a53a11f2182b812250d9470aa4ced536d7fcfb99 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 11 Mar 2019 17:42:24 -0400 Subject: [PATCH 046/189] zebra: Make show nexthop-group command more readable Put some whitespace into the command output so that we can read it a little bit easier. Signed-off-by: Stephen Worley --- zebra/zebra_vty.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b0b888381c78..cf728a649d63 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1115,14 +1115,13 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, if (nhe->vrf_id != zvrf->vrf->vrf_id) continue; - vty_out(vty, - "Group: %u ID: %u RefCnt: %d Valid: %d Installed: %d\n", - nhe->dplane_ref, nhe->id, nhe->refcnt, + vty_out(vty, "Group: %u ID: %u\n", nhe->dplane_ref, nhe->id); + vty_out(vty, "\tRefCnt: %d\n", nhe->refcnt); + vty_out(vty, "\tValid: %d, Installed %d\n", nhe->flags & NEXTHOP_GROUP_VALID, nhe->flags & NEXTHOP_GROUP_INSTALLED); - for (ALL_NEXTHOPS(nhe->nhg, nhop)) { - vty_out(vty, " "); + vty_out(vty, "\t"); nexthop_group_write_nexthop(vty, nhop); } } From 2614bf87643e1f019fb337fab5fe45c3be5752be Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 13:46:05 -0700 Subject: [PATCH 047/189] 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(-) diff --git a/zebra/interface.c b/zebra/interface.c index 6b77f3c871ea..3eb0e68537ff 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 270cc868c0ae..7dccaeaccb50 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 73260ee18be4..b2712d52f1bb 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 ece1e1ccd58a..5704cf0e232c 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 a7a97f5529a5..8b3f6502a197 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 df1f3df091aa..8decb2210df1 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 cf728a649d63..067b7a12a878 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); From f44088c33e2984d5dc9e5091ba1452e1aa72d2a8 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 13 Mar 2019 10:21:41 -0400 Subject: [PATCH 048/189] zebra: Fix where the flags are set for new nexthop entries We were setting the flags in a couple different places for nexthop entries. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 2 ++ zebra/zebra_nhg.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b2712d52f1bb..5bcad6ea9aa3 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2324,7 +2324,9 @@ 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); } else if (h->nlmsg_type == RTM_DELNEXTHOP) { if (!nhe) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 5704cf0e232c..1ddfcc74560c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -96,9 +96,6 @@ static void *zebra_nhg_alloc(void *arg) 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; } From 351486633880f1fac39ae10e49b26a1c5e49bc7c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 13 Mar 2019 10:26:30 -0400 Subject: [PATCH 049/189] zebra: Change wording in duplicate error message Changed to the wording in the duplicate error message since its techincally possible we get could try to create a dupe from somewhere else besides the kernel in the future. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1ddfcc74560c..7800ecd2598c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -256,7 +256,7 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, */ flog_warn( EC_ZEBRA_DUPLICATE_NHG_MESSAGE, - "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring", + "Nexthop Group from with ID (%d) is a duplicate, ignoring", id); return NULL; } From 51d80884482007f380bd12b4494c893cfd813583 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 15 Mar 2019 12:23:51 -0400 Subject: [PATCH 050/189] zebra: Give Nexthop Group Hash entries a defined memory type The nexthop group hash entries were using the "TMP" memory type. Declared one for them and updated to use it. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 7800ecd2598c..2da007fb0477 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -27,6 +27,7 @@ #include "lib/routemap.h" #include "lib/mpls.h" #include "lib/jhash.h" +#include "lib/debug.h" #include "zebra/connected.h" #include "zebra/debug.h" @@ -34,9 +35,12 @@ #include "zebra/zebra_nhg.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" +#include "zebra/zebra_memory.h" +#include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra_errors.h" +DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table * @@ -84,7 +88,7 @@ static void *zebra_nhg_alloc(void *arg) struct nhg_hash_entry *nhe; struct nhg_hash_entry *copy = arg; - nhe = XCALLOC(MTYPE_TMP, sizeof(struct nhg_hash_entry)); + nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry)); pthread_mutex_lock(&lock); /* Lock, set the id counter from kernel */ if (copy->id) { @@ -277,7 +281,8 @@ void zebra_nhg_free(void *arg) nhe = (struct nhg_hash_entry *)arg; nexthops_free(nhe->nhg.nexthop); - XFREE(MTYPE_TMP, nhe); + + XFREE(MTYPE_NHG, nhe); } /** From c4239c05c0e414560361b375fa3606cf0cfcfabb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 19 Mar 2019 16:43:27 -0400 Subject: [PATCH 051/189] zebra: Make bad address family log message more clear The message for an invalid address family on a nexthop gateway did not specify that is what for the gateway specifically. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5bcad6ea9aa3..52c3b706e06e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2126,7 +2126,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, default: flog_warn( EC_ZEBRA_BAD_NHG_MESSAGE, - "Nexthop with bad address family (%d) received from kernel", + "Nexthop gateway with bad address family (%d) received from kernel", family); // TODO: Different return value? return nh; From 77b76fc900db6db8b6a5f2f5a795123a0be547d7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 19 Mar 2019 17:06:01 -0400 Subject: [PATCH 052/189] 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(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2da007fb0477..df93557ad8aa 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 8b3f6502a197..761ed70d1a32 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 8decb2210df1..ff7a3a98dac9 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 067b7a12a878..7022b9d57d8c 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; } From e8b0e4201e8a5793b103c2944d19f7761932a521 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 20 Mar 2019 13:03:22 -0400 Subject: [PATCH 053/189] zebra: Add afi value for all nexthops sent/received Since nexthops are always going to need to be address family specific unless they are only a group, we have to address this when we receive and send them. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 52c3b706e06e..c8d392b4bb65 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1910,30 +1910,30 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) // TODO: IF not a group const struct nexthop_group nhg = nhe->nhg; const struct nexthop *nh = nhg.nexthop; - const struct prefix *dest_p; - unsigned char family = 0; + + if (nhe->afi == AFI_IP) + req.nhm.nh_family = AF_INET; + else if (nhe->afi == AFI_IP6) + req.nhm.nh_family = AF_INET6; switch (nh->type) { // TODO: Need AF for just index also // just use dest? - case NEXTHOP_TYPE_IFINDEX: - dest_p = dplane_ctx_get_dest(ctx); - family = PREFIX_FAMILY(dest_p); - break; case NEXTHOP_TYPE_IPV4_IFINDEX: - family = AF_INET; addattr_l(&req.n, sizeof(req), NHA_GATEWAY, &nh->gate.ipv4, IPV4_MAX_BYTELEN); break; case NEXTHOP_TYPE_IPV6_IFINDEX: - family = AF_INET6; addattr_l(&req.n, sizeof(req), NHA_GATEWAY, &nh->gate.ipv6, IPV6_MAX_BYTELEN); break; case NEXTHOP_TYPE_BLACKHOLE: - family = AF_UNSPEC; + // TODO: Handle this addattr_l(&req.n, sizeof(req), NHA_BLACKHOLE, NULL, 0); break; + case NEXTHOP_TYPE_IFINDEX: + /* Don't need anymore info for this */ + break; case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV6: flog_err( @@ -1943,7 +1943,6 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) break; } - req.nhm.nh_family = family; req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_type(ctx)); addattr32(&req.n, sizeof(req), NHA_OIF, nh->ifindex); @@ -2224,6 +2223,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* nexthop group id */ uint32_t id; unsigned char family; + afi_t afi = AFI_UNSPEC; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; /* struct for nexthop group abstraction */ @@ -2262,13 +2262,15 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* 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 */ + family = nhm->nh_family; + + afi = family2afi(family); + nhe = zebra_nhg_lookup_id(id); if (h->nlmsg_type == RTM_NEWNEXTHOP) { @@ -2310,7 +2312,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) nexthop_group_copy(&nhe->nhg, &nhg); } else { /* This is a new nexthop group */ - nhe = zebra_nhg_find(&nhg, nh.vrf_id, id); + nhe = zebra_nhg_find(&nhg, nh.vrf_id, afi, id); if (nhe) { nhe->is_kernel_nh = true; } else { From a3267f8b6e939445b016a9dd81e23a63691a10bf Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 20 Mar 2019 13:09:15 -0400 Subject: [PATCH 054/189] zebra: Check if a nexthop was added to the nhg Before doing anything with our tables, less make sure we even added anything to the group. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c8d392b4bb65..7a30178ecb3a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2127,7 +2127,6 @@ 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); - // TODO: Different return value? return nh; } gate = RTA_DATA(tb[NHA_GATEWAY]); @@ -2298,12 +2297,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) 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 */ From 50cfa27f1b7140edade4b50d94a93c84dee3e267 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 21 Mar 2019 10:33:42 -0400 Subject: [PATCH 055/189] include: Add nexthop.h to the include automake file Add linux header nexthop.h to the automake file under include/. Signed-off-by: Stephen Worley --- include/subdir.am | 1 + 1 file changed, 1 insertion(+) diff --git a/include/subdir.am b/include/subdir.am index 0d7fed28529e..b1ca1be54fdb 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -6,6 +6,7 @@ noinst_HEADERS += \ include/linux/mpls_iptunnel.h \ include/linux/neighbour.h \ include/linux/netlink.h \ + include/linux/nexthop.h \ include/linux/rtnetlink.h \ include/linux/socket.h \ include/linux/net_namespace.h \ From 3119f6a11455b9c5648167f4c8293476be9c5a9e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 21 Mar 2019 10:43:16 -0400 Subject: [PATCH 056/189] zebra: Add dependency information for nexthop group hash entries We treat "groups" from the kernel here as a dependency list. Each hash entry, if its a group from the kernel, has a list of any other nexthop hash entries that are in its group. A non-group nexthop from the kernel will have its dependency list set to NULL. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-- zebra/zebra_nhg.h | 20 +++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index df93557ad8aa..df66fac8a68b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -41,6 +41,61 @@ #include "zebra_errors.h" DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); +DEFINE_MTYPE_STATIC(ZEBRA, NHG_DEPENDS, "Nexthop Group Entry Depends"); + +/** + * nhg_depend_add() - Add a new dependency to the nhg_hash_entry + * + * @nhg_depend: List we are adding the dependency to + * @depends: Dependency we are adding + * + * Return: Newly created nhg_depend + */ +struct nhg_depend *nhg_depend_add(struct list *nhg_depends, + struct nhg_hash_entry *depend) +{ + struct nhg_depend *nhg_dp = NULL; + + nhg_dp = nhg_depend_new(); + nhg_dp->nhe = depend; + + listnode_add(nhg_depends, nhg_dp); + return nhg_dp; +} + +/** + * nhg_depend_new() - Allocate a new nhg_depend struct + * + * Return: Allocated nhg_depend struct + */ +struct nhg_depend *nhg_depend_new(void) +{ + return XCALLOC(MTYPE_NHG_DEPENDS, sizeof(struct nhg_depend)); +} + +/** + * nhg_depend_free() - Free the nhg_depend struct + */ +void nhg_depend_free(struct nhg_depend *depends) +{ + XFREE(MTYPE_NHG_DEPENDS, depends); +} + +/** + * nhg_depend_new_list() - Allocate a new list for nhg_depends + * + * Return: Allocated nhg_depend list + */ +struct list *nhg_depend_new_list() +{ + struct list *nhg_depends = NULL; + + nhg_depends = list_new(); + nhg_depends->del = (void (*)(void *))nhg_depend_free; + + return nhg_depends; +} + /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table * @@ -105,15 +160,26 @@ static void *zebra_nhg_alloc(void *arg) } pthread_mutex_unlock(&lock); + nhe->nhg_depends = NULL; + nhe->nhg.nexthop = NULL; + + 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->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(); nhe->ifp = NULL; - nhe->nhg.nexthop = NULL; - nexthop_group_copy(&nhe->nhg, ©->nhg); /* Add to id table as well */ zebra_nhg_insert_id(nhe); @@ -168,7 +234,6 @@ uint32_t zebra_nhg_hash_key(const void *arg) key = jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key); - return key; } @@ -286,6 +351,9 @@ 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); XFREE(MTYPE_NHG, nhe); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 761ed70d1a32..f8cd3bb0497c 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -48,6 +48,13 @@ struct nhg_hash_entry { uint32_t dplane_ref; uint32_t flags; + + /* Dependency list for other entries. + * For instance a group with two + * nexthops will have two dependencies + * pointing to those nhg_hash_entries. + */ + struct list *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 @@ -68,9 +75,22 @@ struct nhg_hash_entry { #define NEXTHOP_GROUP_QUEUED 0x4 }; +/* Struct for dependency nexthop */ +struct nhg_depend { + struct nhg_hash_entry *nhe; +}; + + 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 struct list *nhg_depend_new_list(void); + extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id); extern int zebra_nhg_insert_id(struct nhg_hash_entry *nhe); From 85f5e76175f190ef13b7d883a256612380574ca6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 21 Mar 2019 10:47:19 -0400 Subject: [PATCH 057/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7a30178ecb3a..581dae710d11 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 df66fac8a68b..82bbef391166 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 f8cd3bb0497c..e741cc0cfc1d 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 ff7a3a98dac9..d71239abe9ce 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; } From cced3a2d2911bbf9d2adf3b2b47519b9cdc2c0d3 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 21 Mar 2019 10:52:11 -0400 Subject: [PATCH 058/189] zebra: Make show nexthop-group list all nexthop hash entries Add an option to not specify the afi in the show nexthop-group command so that it shows all nexthops, including groups. This is how iproute2 does it. If the afi is given, it will only show single nexthops since groups are AF_UNSPEC. Signed-off-by: Stephen Worley --- zebra/zebra_vty.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7022b9d57d8c..7cf82118dfc5 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1112,7 +1112,7 @@ 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) + if (afi && nhe->afi != afi) continue; if (nhe->vrf_id != zvrf->vrf->vrf_id) @@ -1126,6 +1126,18 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, if (nhe->ifp) 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; + vty_out(vty, "\tDepends:"); + for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, dp_node, + n_dp)) { + vty_out(vty, " (%u)", n_dp->nhe->id); + } + vty_out(vty, "\n"); + } + for (ALL_NEXTHOPS(nhe->nhg, nhop)) { vty_out(vty, "\t"); nexthop_group_write_nexthop(vty, nhop); @@ -1137,14 +1149,20 @@ 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; + + afi_t afi = 0; + if (v4) + afi = AFI_IP; + else if (v6) + afi = AFI_IP6; + struct zebra_vrf *zvrf; if (vrf_all) { From b599cd2acceb4ac96e4d3569bb1caaea4f51f266 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 22 Mar 2019 13:07:22 -0400 Subject: [PATCH 059/189] zebra: Add helper functions for freeing the members of nexthop group hash entries Add some functions that can be called to free everything that should have been allocated in a nexthop group hash entry. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 60 ++++++++++++++++++++++++++++++----------------- zebra/zebra_nhg.h | 3 +++ 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 82bbef391166..789e371da52a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -328,38 +328,54 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, lookup.id = id; lookup.vrf_id = vrf_id; lookup.afi = afi; - lookup.nhg = *nhg; - lookup.nhg_depends = NULL; + lookup.nhg = nhg; + lookup.nhg_depends = nhg_depends; - if (dep_count) - lookup.nhg_depends = nhg_depends; - - nhe = hash_lookup(zrouter.nhgs, &lookup); + if (id) + nhe = zebra_nhg_lookup_id(id); + else + 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 with ID (%d) is a duplicate, ignoring", - id); - if (lookup.nhg_depends) - list_delete(&lookup.nhg_depends); - - return NULL; - } + zebra_nhg_free_group_depends(nhg, nhg_depends); } return nhe; } +/** + * 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 + */ +void zebra_nhg_free_group_depends(struct nexthop_group *nhg, + struct list *nhg_depends) +{ + if (nhg_depends) + list_delete(&nhg_depends); + if (nhg) { + if (nhg->nexthop) + nexthops_free(nhg->nexthop); + nexthop_group_delete(&nhg); + } +} + +/** + * zebra_nhg_free_members() - Free all members in the hash entry struct + * + * @nhe: Nexthop group hash entry + * + * Just use this to free everything but the entry itself. + */ +void zebra_nhg_free_members(struct nhg_hash_entry *nhe) +{ + zebra_nhg_free_group_depends(nhe->nhg, nhe->nhg_depends); +} + /** * zebra_nhg_free() - Free the nexthop group hash entry * diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index e741cc0cfc1d..287aaf275f79 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -104,6 +104,9 @@ 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_group_depends(struct nexthop_group *nhg, + struct list *nhg_depends); +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); From 8e401b251f25be5d9daceab12c73b760a771df6e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 22 Mar 2019 13:11:07 -0400 Subject: [PATCH 060/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 581dae710d11..6753a22eccef 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 f20242bfc2c4..0e806ff7f74e 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 789e371da52a..522bf6a9a253 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 287aaf275f79..634a416e1bef 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 d71239abe9ce..e882c9d69441 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 7cf82118dfc5..c2a9d091d2de 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); } From 55eeb2ae7f56d7ecfa714d661d81e3ca0fb87ebc Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 22 Mar 2019 14:00:25 -0400 Subject: [PATCH 061/189] zebra: Make nexthop group vrf VRF_DEFAULT Nexthop groups can have nexthops in different vrf's. So, let's make the group vrf_id just be VRF_DEFAULT for hash lookup purposes. Set vrf_id to be VRF_DEFAULT for every message. If its a new nextop, set the vrf to be the appropriate thing, otherwise its a group and can just be left as default. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6753a22eccef..0d6b9b7ba21b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2247,6 +2247,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; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; /* struct for nexthop group abstraction */ @@ -2332,7 +2333,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) 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 { flog_warn( @@ -2363,8 +2364,8 @@ 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, nhg->nexthop->vrf_id, afi, id, - nhg_depends, dep_count); + nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends, + dep_count); if (!nhe) { flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, From d6e0094f88e2d80c257388bf88993ccc077f2b5c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 19:28:23 -0400 Subject: [PATCH 062/189] zebra: Add function to duplicate nhg dependencies Add a function to duplicate a nhg dependency linked list. We will use this for duplicating the dependency list rather than the linked list dup function in lib/linkedlist. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 22 ++++++++++++++++++++++ zebra/zebra_nhg.h | 1 + 2 files changed, 23 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 522bf6a9a253..43be8e126f69 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -96,6 +96,28 @@ struct list *nhg_depend_new_list() return nhg_depends; } +/** + * nhg_depend_dup_list() - Duplicate the dependency linked list + * + * @from: List to duplicate + * + * Return: New list + */ +struct list *nhg_depend_dup_list(struct list *from) +{ + 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; +} + /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table * diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 634a416e1bef..559fadf061be 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -90,6 +90,7 @@ extern struct nhg_depend *nhg_depend_new(void); extern void nhg_depend_free(struct nhg_depend *depends); 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); From a71289508a9783f403ef4a5bd6c5fd7e02a9c42d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 19:32:15 -0400 Subject: [PATCH 063/189] zebra: Make nexthop ctx use nhg_depend_dup_list Update the dataplane nexthop ctx to use the nhg_depend_dup_list() function for copying over the dependencies into its context. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 0e806ff7f74e..57faca8bb443 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1517,10 +1517,12 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, 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); + ctx->u.rinfo.zd_nhe.nhg_depends = + nhg_depend_dup_list(nhe->nhg_depends); - /* Extract ns info - can't use pointers to 'core' structs */ + /* Extract ns info - can't use pointers to 'core' + structs */ zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; // TODO: Might not need to mark this as an update, since From 565ce0d3c7ff8634851e91791f7815cb0485ecfb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 19:35:08 -0400 Subject: [PATCH 064/189] zebra: Add functionality to send groups to kernel Add functionality to allow us to send nexthop groups to the kernel. It creates a nexthop_grp array based on the dependency list in the nhg_hash_entry and then shoves that into the netlink message. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 97 +++++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 0d6b9b7ba21b..42daefeea9ef 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1867,6 +1867,33 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) return suc; } +/** + * _netlink_nexthop_build_group() - Build a nexthop_grp struct for a nlmsg + * + * @n: Netlink message header struct + * @req_size: Size allocated for this message + * @nhg_depends: List of entry dependencies + */ +static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, + struct list *nhg_depends) +{ + 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; + } + } + + addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp)); +} + /** * netlink_nexthop() - Nexthop change via the netlink interface * @@ -1904,44 +1931,49 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) addattr32(&req.n, sizeof(req), NHA_ID, nhe->id); if (cmd == RTM_NEWNEXTHOP) { - const struct nexthop *nh = nhe->nhg->nexthop; + if (nhe->nhg_depends) { + _netlink_nexthop_build_group(&req.n, sizeof(req), + nhe->nhg_depends); + } else { + const struct nexthop *nh = nhe->nhg->nexthop; - if (nhe->afi == AFI_IP) - req.nhm.nh_family = AF_INET; - else if (nhe->afi == AFI_IP6) - req.nhm.nh_family = AF_INET6; + if (nhe->afi == AFI_IP) + req.nhm.nh_family = AF_INET; + else if (nhe->afi == AFI_IP6) + req.nhm.nh_family = AF_INET6; - switch (nh->type) { - case NEXTHOP_TYPE_IPV4_IFINDEX: - addattr_l(&req.n, sizeof(req), NHA_GATEWAY, - &nh->gate.ipv4, IPV4_MAX_BYTELEN); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - addattr_l(&req.n, sizeof(req), NHA_GATEWAY, - &nh->gate.ipv6, IPV6_MAX_BYTELEN); - break; - case NEXTHOP_TYPE_BLACKHOLE: - // TODO: Handle this - addattr_l(&req.n, sizeof(req), NHA_BLACKHOLE, NULL, 0); - break; - case NEXTHOP_TYPE_IFINDEX: - /* Don't need anymore info for this */ - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV6: - flog_err( - EC_ZEBRA_NHG_FIB_UPDATE, - "Context received for kernel nexthop update without an interface"); - return -1; - break; + switch (nh->type) { + case NEXTHOP_TYPE_IPV4_IFINDEX: + addattr_l(&req.n, sizeof(req), NHA_GATEWAY, + &nh->gate.ipv4, IPV4_MAX_BYTELEN); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + addattr_l(&req.n, sizeof(req), NHA_GATEWAY, + &nh->gate.ipv6, IPV6_MAX_BYTELEN); + break; + case NEXTHOP_TYPE_BLACKHOLE: + // TODO: Handle this + addattr_l(&req.n, sizeof(req), NHA_BLACKHOLE, + NULL, 0); + break; + case NEXTHOP_TYPE_IFINDEX: + /* Don't need anymore info for this */ + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + flog_err( + EC_ZEBRA_NHG_FIB_UPDATE, + "Context received for kernel nexthop update without an interface"); + return -1; + break; + } + + addattr32(&req.n, sizeof(req), NHA_OIF, nh->ifindex); + // TODO: Handle Encap } req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_type(ctx)); - addattr32(&req.n, sizeof(req), NHA_OIF, nh->ifindex); - - // TODO: Handle Encap - } else if (cmd != RTM_DELNEXTHOP) { flog_err( EC_ZEBRA_NHG_FIB_UPDATE, @@ -2354,6 +2386,7 @@ 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); From 8f8a806fba721f9d363416048e38b7c87e8e0aea Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 19:38:20 -0400 Subject: [PATCH 065/189] zebra: Make wording for depend functions clearer Fix a couple functions that were using depends (plural) rather than depend(singular) in their wording. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 43be8e126f69..140e6a9abf92 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -46,8 +46,8 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG_DEPENDS, "Nexthop Group Entry Depends"); /** * nhg_depend_add() - Add a new dependency to the nhg_hash_entry * - * @nhg_depend: List we are adding the dependency to - * @depends: Dependency we are adding + * @nhg_depends: List we are adding the dependency to + * @depend: Dependency we are adding * * Return: Newly created nhg_depend */ @@ -76,9 +76,9 @@ struct nhg_depend *nhg_depend_new(void) /** * nhg_depend_free() - Free the nhg_depend struct */ -void nhg_depend_free(struct nhg_depend *depends) +void nhg_depend_free(struct nhg_depend *depend) { - XFREE(MTYPE_NHG_DEPENDS, depends); + XFREE(MTYPE_NHG_DEPENDS, depend); } /** From 2d6cd1f007c860ad4c76e7efbbb0bf5b4226af0c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 19:40:23 -0400 Subject: [PATCH 066/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 42daefeea9ef..ea81d180db52 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 140e6a9abf92..3c78ce525310 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 e882c9d69441..a5b939baa9a6 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++; From fdee485ad02197b9ef020b0a25d09cbb4e639b06 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 28 Mar 2019 15:18:28 -0400 Subject: [PATCH 067/189] zebra: Make kernel debug nexthop standardized Make the the kernel debug zlog for nexthop messages from the kernel more aligned with the route message kernel debug zlog. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ea81d180db52..3e377eb770ab 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2322,14 +2322,16 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* We use the ID key'd nhg table for kernel updates */ id = *((uint32_t *)RTA_DATA(tb[NHA_ID])); - if (IS_ZEBRA_DEBUG_KERNEL) { - zlog_debug("Nexthop ID (%u) update from the kernel", id); - } - family = nhm->nh_family; afi = family2afi(family); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s ID (%u) %s NS %u", + nl_msg_type_to_str(h->nlmsg_type), id, + nl_family_to_str(family), ns_id); + + nhe = zebra_nhg_lookup_id(id); if (h->nlmsg_type == RTM_NEWNEXTHOP) { From 5bd81e4c915b1620e4d190f4b688cf10c53429c5 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 28 Mar 2019 15:20:29 -0400 Subject: [PATCH 068/189] zebra: Move id counter into zebra_nhg_find() Move the id counter further up into zebra_nhg_find() so that it is still incremented if we receive a duplicate that never would get allocated. The kernel will still use the dup, so we have to account for that in our id counter. Also, if we don't create a new entry, reset the id back to where it was when zebra_nhg_find() was called. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 49 +++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3c78ce525310..c6117453a2b7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -158,29 +158,13 @@ int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) 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 = XCALLOC(MTYPE_NHG, 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; - } else { - nhe->id = ++id_counter; - } - pthread_mutex_unlock(&lock); + + nhe->id = copy->id; nhe->nhg_depends = NULL; @@ -339,10 +323,31 @@ 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) { + /* 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 = {0}; 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; + + if (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 { + lookup.id = ++id_counter; + } - lookup.id = id; lookup.vrf_id = vrf_id; lookup.afi = afi; lookup.nhg = nhg; @@ -353,6 +358,12 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, else nhe = hash_lookup(zrouter.nhgs, &lookup); + /* If it found an nhe in our tables, this new ID is unused */ + if (nhe) + id_counter = old_id_counter; + + pthread_mutex_unlock(&lock); + if (!nhe) nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); From 9ed6c34a871379f085fc610f3f2d895c80d5064e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 10:46:50 -0400 Subject: [PATCH 069/189] zebra: Pass is_kernel_nh to zebra_nhg_find() Pass a boolean to zebra_nhg_find(), indicating whether the nhg is being lookedup from the kernel side or not. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 8 +++++--- zebra/zebra_nhg.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c6117453a2b7..54f31a6c623c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -177,7 +177,7 @@ static void *zebra_nhg_alloc(void *arg) nhe->vrf_id = copy->vrf_id; nhe->afi = copy->afi; nhe->refcnt = 0; - nhe->is_kernel_nh = false; + nhe->is_kernel_nh = copy->is_kernel_nh; nhe->dplane_ref = zebra_router_get_next_sequence(); nhe->ifp = NULL; @@ -298,7 +298,7 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) * 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 + * @is_kernel_nh: Was the nexthop created by the kernel * * Return: Hash entry found or created * @@ -321,7 +321,8 @@ 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, int dep_count) + struct list *nhg_depends, + bool is_kernel_nh) { /* lock for getiing and setting the id */ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; @@ -352,6 +353,7 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, lookup.afi = afi; lookup.nhg = nhg; lookup.nhg_depends = nhg_depends; + lookup.is_kernel_nh = is_kernel_nh; if (id) nhe = zebra_nhg_lookup_id(id); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 559fadf061be..4efb1b08e5c7 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -103,7 +103,7 @@ 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, int dep_count); + uint32_t id, struct list *nhg_depends, bool is_kernel_nh); void zebra_nhg_free_group_depends(struct nexthop_group *nhg, struct list *nhg_depends); From 3057df51bd471798f4c221531112340e11b7fe46 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 10:51:07 -0400 Subject: [PATCH 070/189] zebra: Add function to find/create single nexthop Add a function that allows us to take a single nexthop struct and look that up or create a group and nexthop hash entry with it. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 23 +++++++++++++++++++++++ zebra/zebra_nhg.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 54f31a6c623c..18f5cf3b8dbf 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -372,6 +372,29 @@ struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg, 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) +{ + struct nhg_hash_entry *nhe = NULL; + + struct nexthop_group *nhg = nexthop_group_new(); + + nexthop_group_add_sorted(nhg, nh); + nhe = zebra_nhg_find(nhg, nh->vrf_id, afi, 0, NULL, false); + + nexthop_group_delete(&nhg); + + return nhe; +} + /** * zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group * struct and depends diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 4efb1b08e5c7..8daa2a1ccf52 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -105,6 +105,9 @@ 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); +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_free_members(struct nhg_hash_entry *nhe); From 7286ac02a3023214c0afc3bc8415a31231dae808 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 10:53:14 -0400 Subject: [PATCH 071/189] zebra: Fix hash key type in zebra_nhg We were declaring the hash key as an int rather then uint32_t. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 18f5cf3b8dbf..c149eafea9f7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -229,7 +229,7 @@ uint32_t zebra_nhg_hash_key(const void *arg) { const struct nhg_hash_entry *nhe = arg; - int key = 0x5a351234; + uint32_t key = 0x5a351234; key = jhash_2words(nhe->vrf_id, nhe->afi, key); From 148a0103c6176b5bb3f3dff531ed06dda754f3c7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 10:55:10 -0400 Subject: [PATCH 072/189] zebra: Add function to lookup ID in depends list Add helper function to allow us to lookup an ID inside of a nhg_hash_entry's dependency list. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c149eafea9f7..92198bad0309 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -118,6 +118,32 @@ struct list *nhg_depend_dup_list(struct list *from) return to; } +/** + * zebra_nhg_depends_lookup_id() - Lookup for an id in the nhg_depends + * linked list of another nhe + * + * @nhe: Nexthop group hash entry with list to look in + * @lookup: ID to look for + * + * Return: Nexthop group hash entry if found + */ +static struct nhg_hash_entry * +zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id) +{ + 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_lookup_id() - Lookup the nexthop group id in the id table * From 20822f9d2e450cebfefbb14cc70a189a52df063c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 10:56:52 -0400 Subject: [PATCH 073/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3e377eb770ab..7917e3046e2d 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 92198bad0309..c698d1099ac0 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 a5b939baa9a6..558dbd33e090 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++; From 7fd392cc4d804aae6bd9d1452ba5b108ecdc70a2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 18:14:20 -0400 Subject: [PATCH 074/189] zebra: Add function to increment nhg refcnt Add function to increment the route reference count for nhg_hash_entry's and to do so recursively if its a group. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 19 ++++++++++++++++++- zebra/zebra_nhg.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c698d1099ac0..a296671068a1 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -522,8 +522,25 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { zebra_nhg_uninstall_kernel(nhe); } +} + +/** + * zebra_nhg_increment_ref() - Increment the reference count + * + * @nhe: Nexthop group hash entry + */ +void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) +{ + if (nhe->nhg_depends) { + struct listnode *ln = NULL; + struct nhg_depend *n_dp = NULL; + + for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, ln, n_dp)) { + zebra_nhg_increment_ref(n_dp->nhe); + } + } - // re->ng = NULL; + nhe->refcnt++; } static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 8daa2a1ccf52..90c7abb3e621 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -114,6 +114,7 @@ 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 int nexthop_active_update(struct route_node *rn, struct route_entry *re); From f54ef6a5ba251ba091a4ec0079008ec7a6f81883 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 29 Mar 2019 18:16:27 -0400 Subject: [PATCH 075/189] zebra: Recursively decrement refcnt on nhe's Recursively decrement the refcnt on nhg_hash_entry's of groups. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index a296671068a1..978870359dd2 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -517,6 +517,15 @@ void zebra_nhg_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; + + for (ALL_LIST_ELEMENTS_RO(nhe->nhg_depends, ln, n_dp)) { + zebra_nhg_decrement_ref(n_dp->nhe); + } + } + nhe->refcnt--; if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { From 86946a2207c3f2c177b478c9cf64f491a922df5c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 1 Apr 2019 12:21:52 -0400 Subject: [PATCH 076/189] 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(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 558dbd33e090..d33b8494b020 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, From ab942eb2853310fa76e1bcdad422eed441adeb00 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 1 Apr 2019 12:24:16 -0400 Subject: [PATCH 077/189] 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(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d33b8494b020..3155570df5e3 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 From 7512f617c7f6e9258f0b8f53f6d556d1e36611e9 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 13:56:38 -0700 Subject: [PATCH 078/189] zebra: Releasing/uninstalling re-work with groups Re-work the code to release/uninstall after the addition of groups. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 978870359dd2..94565f434d36 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -496,15 +496,23 @@ void zebra_nhg_free(void *arg) */ void zebra_nhg_release(struct nhg_hash_entry *nhe) { - if (nhe->refcnt) - flog_err( - EC_ZEBRA_NHG_SYNC, - "Releasing a nexthop group with ID (%u) that we are still using for a route", - nhe->id); + if (!nhe->refcnt) { + zlog_debug("Releasing nexthop group with ID (%u)", nhe->id); + hash_release(zrouter.nhgs, nhe); + hash_release(zrouter.nhgs_id, nhe); + zebra_nhg_free(nhe); + } +} - hash_release(zrouter.nhgs, nhe); - hash_release(zrouter.nhgs_id, nhe); - zebra_nhg_free(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); } /** @@ -529,7 +537,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) nhe->refcnt--; if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { - zebra_nhg_uninstall_kernel(nhe); + zebra_nhg_uninstall_release(nhe); } } @@ -1173,6 +1181,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) nhe = zebra_nhg_lookup_id(id); if (nhe) { + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", @@ -1183,7 +1192,6 @@ 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, @@ -1202,7 +1210,6 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) nhe->id); UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); } - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); break; case DPLANE_OP_ROUTE_INSTALL: case DPLANE_OP_ROUTE_UPDATE: From 0c8215cbab59480616fe31d8a81323070a21137b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 13 May 2019 17:10:34 -0700 Subject: [PATCH 079/189] 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(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 9564321d3822..527039ac63e3 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 4f4d40eb331e..5193c943c4f6 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 7917e3046e2d..f7e72e243ff3 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 57faca8bb443..170f7cfe64a1 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 6ca2a274c6cf..447e9c0d7f3e 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 94565f434d36..56f8c9d85233 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 90c7abb3e621..1cc1c47e3214 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 3155570df5e3..957b7e14f416 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 c2a9d091d2de..106cd6b027b9 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"); } From a15d4c0089a6b8f59932df39357725feadfb9f91 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 13 May 2019 18:13:02 -0700 Subject: [PATCH 080/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f7e72e243ff3..bdf613cef4d4 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 170f7cfe64a1..e4890319d9dd 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 56f8c9d85233..d3204bdf4852 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 1cc1c47e3214..4aa59e7530a4 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 957b7e14f416..7015ff77de70 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 106cd6b027b9..cd099da37e9d 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)) { From fe593b781d8a927bd496c77799312cc64a565141 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 09:53:19 -0700 Subject: [PATCH 081/189] 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(-) diff --git a/zebra/interface.c b/zebra/interface.c index 3eb0e68537ff..8fe7af3f2aca 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 7dccaeaccb50..d5c1e1713193 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 bdf613cef4d4..d2d9060b84c9 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 d3204bdf4852..44265bc5805a 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 4aa59e7530a4..ebdc3a636f23 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 7015ff77de70..898076b01721 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); } From f862383fc9f0055dc068d5374e5efc7b49a23e2e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 10:11:30 -0700 Subject: [PATCH 082/189] zebra: Add interface down marking to NHE's Add functionality to allow an interface down event to mark any dependent NHE's as invalid. Signed-off-by: Stephen Worley --- zebra/interface.c | 12 ++++++++++++ zebra/interface.h | 1 + 2 files changed, 13 insertions(+) diff --git a/zebra/interface.c b/zebra/interface.c index 8fe7af3f2aca..798cb926905e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -983,7 +983,17 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp) return false; } +void if_down_nhg_dependents(const 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) { + zebra_nhg_set_invalid(rb_node_dep->nhe); + } + } } /* Interface is up. */ @@ -1049,6 +1059,8 @@ void if_down(struct interface *ifp) zif->down_count++; quagga_timestamp(2, zif->down_last, sizeof(zif->down_last)); + if_down_nhg_dependents(ifp); + /* Handle interface down for specific types for EVPN. Non-VxLAN * interfaces * are checked to see if (remote) neighbor entries need to be purged diff --git a/zebra/interface.h b/zebra/interface.h index d5c1e1713193..c5614a2a604b 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -441,6 +441,7 @@ 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); From cb50cbc96ee0b6c69e7c80d00c3d26070f4a1651 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 10:12:28 -0700 Subject: [PATCH 083/189] zebra: Just uninstall NHE when refcnt hits zero Just going to uninstall the NHE when refcnt hits zero for now. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 44265bc5805a..376d07535db2 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -605,7 +605,8 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) nhe->refcnt--; if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { - zebra_nhg_uninstall_release(nhe); + zebra_nhg_uninstall_kernel(nhe); + // zebra_nhg_release(nhe); } } From bbb3940ed11d62df8263bb97ef393c1d7de0220b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 12:00:51 -0400 Subject: [PATCH 084/189] 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(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index d2d9060b84c9..db8e28cea0c6 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 898076b01721..96e5816da316 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) { From 7b683a96e4227956cfe6236628885b1421b62781 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 12:11:49 -0400 Subject: [PATCH 085/189] zebra: Put nhe ifp setting inside alloc Put the setting of the ifp on a nexthop group hash entry into the zebra_nhg_alloc() function. It should only be added if its not a group/recursive (it doesn't have any depends) and its nexthop type has an ifindex. This also provides functionality for proto-side ifp setting. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 6 ------ zebra/zebra_nhg.c | 20 +++++++++++++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index db8e28cea0c6..4407167521c2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2447,12 +2447,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) id); 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); } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 376d07535db2..cacbce1785ac 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -308,7 +308,6 @@ static void *zebra_nhg_alloc(void *arg) nhe->refcnt = 0; nhe->is_kernel_nh = copy->is_kernel_nh; nhe->dplane_ref = zebra_router_get_next_sequence(); - nhe->ifp = NULL; /* Attach backpointer to anything that it depends on */ zebra_nhg_dependents_init(nhe); @@ -319,6 +318,25 @@ static void *zebra_nhg_alloc(void *arg) } } + /* Add the ifp now if its not a group or recursive and has ifindex */ + if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop) { + struct interface *ifp = NULL; + + switch (nhe->nhg->nexthop->type) { + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IFINDEX: + ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex, + nhe->vrf_id); + zebra_nhg_set_if(nhe, ifp); + break; + case NEXTHOP_TYPE_BLACKHOLE: + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + break; + } + } + /* Add to id table as well */ zebra_nhg_insert_id(nhe); From ddaee0c7d3ca75040a9b28289a8d961084b000ea Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 12:47:03 -0400 Subject: [PATCH 086/189] zebra: Remove uneeded freeing helper function Removing this function since the new paradigm of everything just being nhg_connected structs makes it not make a lot of sense. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 7 +++++-- zebra/zebra_nhg.c | 31 ++----------------------------- zebra/zebra_nhg.h | 2 -- 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4407167521c2..ae0cf8ab4575 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2399,7 +2399,8 @@ 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); + nexthop_group_free_delete(&nhg); + nhg_connected_head_free(&nhg_depends); return -1; } @@ -2413,12 +2414,14 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) */ zebra_nhg_set_invalid(nhe); - zebra_nhg_free_group_depends(&nhg, &nhg_depends); + nexthop_group_free_delete(&nhg); + nhg_connected_head_free(&nhg_depends); } 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) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index cacbce1785ac..3198fc1dfa33 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -529,32 +529,6 @@ struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi) return nhe; } -/** - * zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group - * struct and depends - * - * @nhg: Nexthop_group - * @nhg_depends: Nexthop group dependency tree head - */ -void zebra_nhg_free_group_depends(struct nexthop_group **nhg, - struct nhg_connected_head *head) -{ - // TODO - // - // - // FIX THIS NAMING - // - // - // - // - // - if (head) - nhg_connected_head_free(head); - - if (nhg) - nexthop_group_free_delete(nhg); -} - /** * zebra_nhg_free_members() - Free all members in the hash entry struct * @@ -564,9 +538,8 @@ 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 + nexthop_group_free_delete(&nhe->nhg); + nhg_connected_head_free(&nhe->nhg_depends); nhg_connected_head_free(&nhe->nhg_dependents); } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index ebdc3a636f23..1f8f63ad679f 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -156,8 +156,6 @@ 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 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); From 8f8d9845c6bc283e5a9f7339f9d3f2884774589b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 13:36:41 -0400 Subject: [PATCH 087/189] lib: Add equals function for nexthop groups Add a function to check whether nexthop groups are equivalent. It does not care about ordering. Also, set any functions that it relies on to take const vars as well. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 25 ++++++++++++++++++++++++- lib/nexthop_group.h | 6 ++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 527039ac63e3..463ab0b881c9 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -94,7 +94,8 @@ uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg) return num; } -struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh) +struct nexthop *nexthop_exists(const struct nexthop_group *nhg, + const struct nexthop *nh) { struct nexthop *nexthop; @@ -106,6 +107,28 @@ struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh) return NULL; } +bool nexthop_group_equal(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2) +{ + struct nexthop *nh = NULL; + + if (nhg1 && !nhg2) + return false; + + if (!nhg1 && !nhg2) + return false; + + if (nexthop_group_nexthop_num(nhg1) != nexthop_group_nexthop_num(nhg2)) + return false; + + for (ALL_NEXTHOPS_PTR(nhg1, nh)) { + if (!nexthop_exists(nhg2, nh)) + return false; + } + + return true; +} + struct nexthop_group *nexthop_group_new(void) { return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group)); diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 5193c943c4f6..be6f50d8a0d3 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -111,8 +111,10 @@ void nexthop_group_disable_vrf(struct vrf *vrf); void nexthop_group_interface_state_change(struct interface *ifp, ifindex_t oldifindex); -extern struct nexthop *nexthop_exists(struct nexthop_group *nhg, - struct nexthop *nh); +extern struct nexthop *nexthop_exists(const struct nexthop_group *nhg, + const struct nexthop *nh); +extern bool nexthop_group_equal(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2); extern struct nexthop_group_cmd *nhgc_find(const char *name); From 7192bb23fba993b072c5e3aabaf5ad6eae523fef Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 13:51:15 -0400 Subject: [PATCH 088/189] zebra: Update nhg_hash_equal to use nexthop_group_equal Update the zebra_nhg_hash_equal() function to use the nexthop_group_equal() function in lib/nexthop_group instead of comparing their depends RB tree. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3198fc1dfa33..eb2454b52f8b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -169,41 +169,6 @@ void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) nhg_connected_head_init(&nhe->nhg_depends); } -/** - * 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 nhg_connected *rb_node_dep = NULL; - - if (zebra_nhg_depends_is_empty(nhe1) - && zebra_nhg_depends_is_empty(nhe2)) - return true; - - 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; - - 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; - } - - return true; -} - unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe) { return nhg_connected_head_count(&nhe->nhg_dependents); @@ -383,7 +348,7 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->afi != nhe2->afi) return false; - if (!zebra_nhg_depends_equal(nhe1, nhe2)) + if (!nexthop_group_equal(nhe1->nhg, nhe2->nhg)) return false; return true; From 3082f99c48abad6e04eaebb8b775e762bd18429a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 11 Apr 2019 13:56:06 -0400 Subject: [PATCH 089/189] zebra: Remove uneeded zebra_nhg_cmp() function Removed a static function that did not need to be there. The nhg_connected_cmp() function provides all the needed functionality for comparing ID's in the RB tree. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index eb2454b52f8b..e5c4520c70d7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -363,10 +363,10 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) } /** - * zebra_nhg_cmp() - Compare the ID's of two nhe's + * nhg_connected cmp() - Compare the ID's of two connected nhg's * - * @nhe1: Nexthop group hash entry #1 - * @nhe2: Nexthop group hash entry #2 + * @con1: Connected group entry #1 + * @con2: Connected group entry #2 * * Return: * - Negative: #1 < #2 @@ -375,16 +375,10 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) * * 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) +static int nhg_connected_cmp(const struct nhg_connected *con1, + const struct nhg_connected *con2) { - return nhe1->id - nhe2->id; -} - -static int nhg_connected_cmp(const struct nhg_connected *dep1, - const struct nhg_connected *dep2) -{ - return zebra_nhg_cmp(dep1->nhe, dep2->nhe); + return (con1->nhe->id - con2->nhe->id); } /** From 13dfea50e4aba145d57ce32247208d7108d5e803 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Apr 2019 19:15:43 -0400 Subject: [PATCH 090/189] 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(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 96e5816da316..6fe87697b2a9 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; } From 085304dc09bad042df987d9fb62272afd993f7fe Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 14:31:17 -0700 Subject: [PATCH 091/189] zebra: RB_FIND then RB_REMOVE nhg_connected Can't RM_REMOVE directly with a key, you need to actually pass the data to be removed. So, lookup with a key first to find the node, then remove it. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index e5c4520c70d7..ebddeb3f9514 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -103,13 +103,16 @@ void nhg_connected_head_del(struct nhg_connected_head *head, struct nhg_hash_entry *depend) { struct nhg_connected lookup = {}; - struct nhg_connected *removed = NULL; + struct nhg_connected *remove = NULL; lookup.nhe = depend; - removed = RB_REMOVE(nhg_connected_head, head, &lookup); + /* Lookup to find the element, then remove it */ + remove = RB_FIND(nhg_connected_head, head, &lookup); + remove = RB_REMOVE(nhg_connected_head, head, remove); - nhg_connected_free(removed); + if (remove) + nhg_connected_free(remove); } void nhg_connected_head_add(struct nhg_connected_head *head, From 18cf7f15d635ba9738e98b7eeb5ff50cfacbec0e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 14:36:48 -0700 Subject: [PATCH 092/189] zebra: Add NULL check before nhg_connected insert Add a check to make sure we allocated the nhg_connected before inserting into the RB tree. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ebddeb3f9514..a23af36b3444 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -122,7 +122,8 @@ void nhg_connected_head_add(struct nhg_connected_head *head, new = nhg_connected_new(depend); - RB_INSERT(nhg_connected_head, head, new); + if (new) + RB_INSERT(nhg_connected_head, head, new); } unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) From 21615102a0ef57a321999c3d1289935e4a1d95d6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 14:40:27 -0700 Subject: [PATCH 093/189] zebra: Add depends/dependents release functions Add some functions to iterate over the depends/dependents RB tree and remove themselves from the other's RB tree. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index a23af36b3444..4d510f487a8a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -173,6 +173,20 @@ void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) nhg_connected_head_init(&nhe->nhg_depends); } +/* Release this nhe from anything that it depends on */ +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; + struct nhg_connected *tmp = NULL; + + RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends, tmp) { + zebra_nhg_dependents_del(rb_node_dep->nhe, nhe); + } + } +} + unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe) { return nhg_connected_head_count(&nhe->nhg_dependents); @@ -217,6 +231,20 @@ void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe) nhg_connected_head_init(&nhe->nhg_dependents); } +/* Release this nhe from anything depending on it */ +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; + struct nhg_connected *tmp = NULL; + + RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, + &nhe->nhg_dependents, tmp) { + zebra_nhg_depends_del(rb_node_dep->nhe, nhe); + } + } +} + /** * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table * From 6ccc2b28efa3223385ae764e667ed9bec1231f85 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 14:42:50 -0700 Subject: [PATCH 094/189] zebra: Del from depends/dependents tree on release Upon release, call the approprate functions to remove itself from depends/dependents trees it is in. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4d510f487a8a..b5fd76b31f3b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -146,9 +146,6 @@ void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend) { nhg_connected_head_del(&from->nhg_depends, depend); - - /* Delete from the dependent tree */ - zebra_nhg_dependents_del(depend, from); } /** @@ -557,12 +554,17 @@ void zebra_nhg_free(void *arg) */ void zebra_nhg_release(struct nhg_hash_entry *nhe) { - if (!nhe->refcnt) { - zlog_debug("Releasing nexthop group with ID (%u)", nhe->id); - hash_release(zrouter.nhgs, nhe); - hash_release(zrouter.nhgs_id, nhe); - zebra_nhg_free(nhe); - } + zlog_debug("Releasing nexthop group with ID (%u)", nhe->id); + + /* Remove it from any lists it may be on */ + zebra_nhg_depends_release(nhe); + zebra_nhg_dependents_release(nhe); + if (nhe->ifp) + if_nhg_dependents_del(nhe->ifp, nhe); + + hash_release(zrouter.nhgs, nhe); + hash_release(zrouter.nhgs_id, nhe); + zebra_nhg_free(nhe); } /** @@ -588,7 +590,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) if (!nhe->is_kernel_nh && nhe->refcnt <= 0) { zebra_nhg_uninstall_kernel(nhe); - // zebra_nhg_release(nhe); + zebra_nhg_release(nhe); } } From 71593b3f0f67b797fa90571fa7c5a56cd5d8ef89 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 14:45:09 -0700 Subject: [PATCH 095/189] zebra: Free the nhe dataplane ctx always Free the nhe dataplane context no matter whether the operation was successful or not. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index b5fd76b31f3b..7373805d2ca8 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1306,13 +1306,12 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NONE: break; } - dplane_ctx_fini(&ctx); - - } else { + } else flog_err( EC_ZEBRA_NHG_SYNC, "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table", dplane_op2str(op), id); - } + + dplane_ctx_fini(&ctx); } From e22e80010ee4226cbb4c1cb570d520ff071add89 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:03:29 -0700 Subject: [PATCH 096/189] 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(-) diff --git a/lib/route_types.txt b/lib/route_types.txt index 59f3a91cf0f5..71d0a46449aa 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 798cb926905e..94f5cb58cd65 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 c5614a2a604b..d5c1e1713193 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 6b8097dd131e..2652b12abf2d 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 ae0cf8ab4575..419e8ffb6e2a 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 e4890319d9dd..21427b80631f 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 447e9c0d7f3e..d0fde958e4c9 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 7373805d2ca8..67f72d1e8283 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 1f8f63ad679f..e287dacfdb7e 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 6fe87697b2a9..6276ed34785f 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 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) 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); } From a6e6a6d825f98ecd3c074dfa473aec2d5da4cdb1 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 22 Apr 2019 15:42:10 -0400 Subject: [PATCH 097/189] zebra: Fix nhg ifindex setting and checking We were only setting and checking the ifindex if the nexthop had an *_IFINDEX type. However, when nexthop active checking is done, the non-*_IFINDEX types can also obtain a nexthop with an ifindex and are thus valid too. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 8 +++++--- zebra/zebra_nhg.c | 19 +++++-------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 419e8ffb6e2a..83e3fd558b12 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1962,10 +1962,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) req.nhm.nh_family = AF_INET6; switch (nh->type) { + case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: addattr_l(&req.n, sizeof(req), NHA_GATEWAY, &nh->gate.ipv4, IPV4_MAX_BYTELEN); break; + case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: addattr_l(&req.n, sizeof(req), NHA_GATEWAY, &nh->gate.ipv6, IPV6_MAX_BYTELEN); @@ -1978,13 +1980,13 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) case NEXTHOP_TYPE_IFINDEX: /* Don't need anymore info for this */ break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV6: + } + + if (!nh->ifindex) { flog_err( EC_ZEBRA_NHG_FIB_UPDATE, "Context received for kernel nexthop update without an interface"); return -1; - break; } addattr32(&req.n, sizeof(req), NHA_OIF, nh->ifindex); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 67f72d1e8283..94d41ba24611 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -312,22 +312,13 @@ static void *zebra_nhg_alloc(void *arg) } /* Add the ifp now if its not a group or recursive and has ifindex */ - if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop) { + if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop + && nhe->nhg->nexthop->ifindex) { struct interface *ifp = NULL; - switch (nhe->nhg->nexthop->type) { - case NEXTHOP_TYPE_IPV4_IFINDEX: - case NEXTHOP_TYPE_IPV6_IFINDEX: - case NEXTHOP_TYPE_IFINDEX: - ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex, - nhe->vrf_id); - zebra_nhg_set_if(nhe, ifp); - break; - case NEXTHOP_TYPE_BLACKHOLE: - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV6: - break; - } + ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex, + nhe->vrf_id); + zebra_nhg_set_if(nhe, ifp); } /* Add to id table as well */ From de3f54881950c999ba5034bf525783a2c9d8e931 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:42:39 -0700 Subject: [PATCH 098/189] zebra: Use NHE id on kernel route sends If the kernel supports nexthop objects, send the route using an nhg_hash_entry ID instead. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 7 +++++++ zebra/zebra_dplane.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 83e3fd558b12..5d2d407688c5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1637,6 +1637,13 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) RTA_PAYLOAD(rta)); } + if (dplane_ctx_get_nhe_id(ctx)) { + /* Kernel supports nexthop objects */ + addattr32(&req.n, sizeof(req), RTA_NH_ID, + dplane_ctx_get_nhe_id(ctx)); + goto skip; + } + /* Count overall nexthops so we can decide whether to use singlepath * or multipath case. */ diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 21427b80631f..d3e10bbb5d31 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1525,6 +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; + /* Trying out the sequence number idea, so we can try to detect * when a result is stale. */ From 3230a4dba5f3ee7dfe0d8d12f23b212c62215faa Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 23 Apr 2019 10:24:58 -0400 Subject: [PATCH 099/189] zebra: Check for nh group support in dplane ctx Only queue a nexthop object update if the dataplane supports nexthop objects. Otherwise, mark it as a success since we should only me sending them to the kernel if we think they are valid anywyay. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index d3e10bbb5d31..f818ed5bc6e9 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1593,6 +1593,11 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, structs */ zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; + if (!zns->supports_nh) { + ret = EOPNOTSUPP; + goto done; + } + // TODO: Might not need to mark this as an update, since // it probably won't require two messages dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE)); @@ -1885,8 +1890,12 @@ dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) if (ret == AOK) result = ZEBRA_DPLANE_REQUEST_QUEUED; else { - atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1, - memory_order_relaxed); + if (ret == EOPNOTSUPP) + result = ZEBRA_DPLANE_REQUEST_SUCCESS; + else + atomic_fetch_add_explicit( + &zdplane_info.dg_nexthop_errors, 1, + memory_order_relaxed); if (ctx) dplane_ctx_free(&ctx); } From 1c3d2890408e05f60b4864a93a1dff0c23ab346c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 9 May 2019 12:48:24 -0400 Subject: [PATCH 100/189] zebra: Update snmp code to use nexthop pointer Update all nexthop_group struct's in zebra_snmp.c to use a pointer to its nexthop. Signed-off-by: Stephen Worley --- zebra/zebra_snmp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 74eab765c8c8..56c76643283f 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -285,8 +285,8 @@ static void check_replace(struct route_node *np2, struct route_entry *re2, return; } - if (in_addr_cmp((uint8_t *)&(*re)->ng.nexthop->gate.ipv4, - (uint8_t *)&re2->ng.nexthop->gate.ipv4) + if (in_addr_cmp((uint8_t *)&(*re)->ng->nexthop->gate.ipv4, + (uint8_t *)&re2->ng->nexthop->gate.ipv4) <= 0) return; @@ -372,7 +372,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], (uint8_t *)&dest)) { RNODE_FOREACH_RE (*np, *re) { if (!in_addr_cmp((uint8_t *)&(*re) - ->ng.nexthop + ->ng->nexthop ->gate.ipv4, (uint8_t *)&nexthop)) if (proto @@ -406,7 +406,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], || ((policy == policy2) && (proto < proto2)) || ((policy == policy2) && (proto == proto2) && (in_addr_cmp( - (uint8_t *)&re2->ng.nexthop + (uint8_t *)&re2->ng->nexthop ->gate.ipv4, (uint8_t *)&nexthop) >= 0))) @@ -432,7 +432,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], { struct nexthop *nexthop; - nexthop = (*re)->ng.nexthop; + nexthop = (*re)->ng->nexthop; if (nexthop) { pnt = (uint8_t *)&nexthop->gate.ipv4; for (i = 0; i < 4; i++) @@ -462,7 +462,7 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, if (!np) return NULL; - nexthop = re->ng.nexthop; + nexthop = re->ng->nexthop; if (!nexthop) return NULL; From 98cda54a9543ea125e5e1eea6621c453f407edb2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:27:40 -0700 Subject: [PATCH 101/189] 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(-) diff --git a/lib/nexthop.h b/lib/nexthop.h index 9dd5fc6fd3f3..5558e857f664 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 463ab0b881c9..c9a8f1af5102 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 be6f50d8a0d3..57a5a975993e 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 5d2d407688c5..89fed59f7614 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 f818ed5bc6e9..429d4c59a1a2 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 94d41ba24611..144decfbb59b 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 e287dacfdb7e..c6ac7d4706aa 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 6276ed34785f..438923e232e2 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) From 7f1abf7926b71ac7c7170883d0d8d0039ba269b0 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:22:53 -0700 Subject: [PATCH 102/189] zebra: Error if the ifp lookup fails for an NHE If the lookup for an interface pointer fails when creating the NHE, log an error message. Signed-off-by: Stephen Worley --- zebra/zebra_errors.c | 6 ++++++ zebra/zebra_errors.h | 1 + zebra/zebra_nhg.c | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 3ca1bf397182..5a0905d59115 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -310,6 +310,12 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Check to see if the nexthop group on the route you tried to install is valid." }, + { + .code = EC_ZEBRA_IF_LOOKUP_FAILED, + .title = "Zebra interface lookup failed", + .description = "Zebra attempted to look up a interface for a particular vrf_id and interface index, but didn't find anything.", + .suggestion = "If you entered a command to trigger this error, make sure you entered the arguments correctly. Check your config file for any potential errors. If these look correct, seek help.", + }, /* Warnings */ { .code = EC_ZEBRAING_LM_PROTO_MISMATCH, diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 1411980ba55b..f9ccc2db282d 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -75,6 +75,7 @@ enum zebra_log_refs { EC_ZEBRA_NHG_TABLE_INSERT_FAILED, EC_ZEBRA_NHG_SYNC, EC_ZEBRA_NHG_FIB_UPDATE, + EC_ZEBRA_IF_LOOKUP_FAILED, /* warnings */ EC_ZEBRA_NS_NOTIFY_READ, EC_ZEBRAING_LM_PROTO_MISMATCH, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 144decfbb59b..f43aa2f31e6d 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -355,7 +355,14 @@ static void *zebra_nhg_alloc(void *arg) ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex, nhe->vrf_id); - zebra_nhg_set_if(nhe, ifp); + if (ifp) + zebra_nhg_set_if(nhe, ifp); + else + flog_err( + EC_ZEBRA_IF_LOOKUP_FAILED, + "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u", + nhe->nhg->nexthop->ifindex, nhe->vrf_id, + nhe->id); } /* Add to id table as well */ From 144a1b34dfc37fdd1174e7a2f150f2315730d8f7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:26:20 -0700 Subject: [PATCH 103/189] 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(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index f43aa2f31e6d..1fd4ec4a9c88 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 c6ac7d4706aa..ef8b2730fbf1 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 438923e232e2..8fe673cb3186 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); From 4505578be0304dd314e96e352be13d0925584497 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:33:04 -0700 Subject: [PATCH 104/189] zebra: Return true if the NHE created, not found In zebra_nhg_find(), if we created a nhg_hash_entry, return true so we know rib-side. Kernel-side, we don't care since it will always just enqueue a context to process later. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 66 ++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1fd4ec4a9c88..3ceb5e33862e 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -478,19 +478,20 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, } -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) +static bool zebra_nhg_find(struct nhg_hash_entry **nhe, 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) { /* 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 = id_counter; + bool created = false; + if (id > id_counter) { /* Increase our counter so we don't try to create * an ID that already exists @@ -509,31 +510,33 @@ zebra_nhg_find(uint32_t id, struct nexthop_group *nhg, lookup.nhg_depends = *nhg_depends; if (id) - nhe = zebra_nhg_lookup_id(id); + (*nhe) = zebra_nhg_lookup_id(id); else - nhe = hash_lookup(zrouter.nhgs, &lookup); + (*nhe) = hash_lookup(zrouter.nhgs, &lookup); /* If it found an nhe in our tables, this new ID is unused */ - if (nhe) + if (*nhe) id_counter = old_id_counter; - if (!nhe) - nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); + if (!(*nhe)) { + (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc); + created = true; + } - return nhe; + return created; } /* 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) +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_group nhg = {}; _nexthop_group_add_sorted(&nhg, nh); - return zebra_nhg_find(id, &nhg, NULL, nh->vrf_id, afi, is_kernel_nh); + return zebra_nhg_find(nhe, id, &nhg, NULL, nh->vrf_id, afi, + is_kernel_nh); } static struct nhg_ctx *nhg_ctx_new() @@ -580,13 +583,15 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) 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); + if (!zebra_nhg_find(&nhe, ctx->id, nhg, &nhg_depends, + ctx->vrf_id, ctx->afi, true)) + nhg_connected_head_free(&nhg_depends); + /* 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); + } else if (!zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi, + ctx->is_kernel_nh)) + nhg_connected_head_free(&nhg_depends); if (nhe) { if (ctx->id != nhe->id) @@ -706,12 +711,15 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) { struct nexthop lookup = {0}; + struct nhg_hash_entry *nhe = NULL; lookup = *nh; /* Clear it, in case its a group */ lookup.next = NULL; lookup.prev = NULL; - return zebra_nhg_find_nexthop(0, &lookup, afi, false); + zebra_nhg_find_nexthop(&nhe, 0, &lookup, afi, false); + + return nhe; } /* Rib-side, you get a nexthop group struct */ @@ -747,9 +755,21 @@ 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; } - nhe = zebra_nhg_find(id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, false); + if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, + false)) + nhg_connected_head_free(&nhg_depends); + return nhe; } From 2f65aee06ad31d720a316f9d7dee90dcdaebcd41 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:47:20 -0700 Subject: [PATCH 105/189] zebra: Don't error on nexthop object support check On startup when we are requesting all nexthop objects from the kernel and it doesn't support that, we should not produce an error message. Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index a81788028e05..23f1a3bf86ca 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -891,15 +891,20 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); - } else - flog_err( - EC_ZEBRA_UNEXPECTED_MESSAGE, - "%s error: %s, type=%s(%u), seq=%u, pid=%u", - nl->name, - safe_strerror(-errnum), - nl_msg_type_to_str(msg_type), - msg_type, err->msg.nlmsg_seq, - err->msg.nlmsg_pid); + } else { + if ((msg_type != RTM_GETNEXTHOP) + || !startup) + flog_err( + EC_ZEBRA_UNEXPECTED_MESSAGE, + "%s error: %s, type=%s(%u), seq=%u, pid=%u", + nl->name, + safe_strerror(-errnum), + nl_msg_type_to_str( + msg_type), + msg_type, + err->msg.nlmsg_seq, + err->msg.nlmsg_pid); + } return -1; } From da1371420204efbdaef17138392b146708cfbf4c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:35:13 -0700 Subject: [PATCH 106/189] zebra: Create a new NHE if the mpls labels change We should create a new NHE if the mpls labels change since we hash on them. This adds the functonality to do that and decrement the refcnt on the old one. Signed-off-by: Stephen Worley --- zebra/zebra_mpls.c | 52 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 6e0c0b8d88de..cbbb02be35d2 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2590,11 +2590,13 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct route_node *rn; struct route_entry *re; struct nexthop *nexthop; + struct nexthop_group new_grp = {}; + struct nhg_hash_entry *nhe = NULL; bool found; + afi_t afi = family2afi(prefix->family); /* Lookup table. */ - table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST, - zvrf_id(zvrf)); + table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); if (!table) return -1; @@ -2610,8 +2612,15 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; + /* + * Copy over current nexthops into a temporary group. + * We can't just change the values here since we are hashing + * on labels. We need to create a whole new group + */ + nexthop_group_copy(&new_grp, re->ng); + found = false; - for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -2625,7 +2634,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, continue; if (!mpls_ftn_update_nexthop(add, nexthop, type, out_label)) - return 0; + break; found = true; break; case NEXTHOP_TYPE_IPV6: @@ -2640,7 +2649,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, continue; if (!mpls_ftn_update_nexthop(add, nexthop, type, out_label)) - return 0; + break; found = true; break; default: @@ -2648,14 +2657,19 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, } } - if (!found) - return -1; + if (found) { + nhe = zebra_nhg_rib_find(0, &new_grp, re->vrf_id, afi); - SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); - rib_queue_add(rn); + zebra_nhg_re_update_ref(re, nhe); - return 0; + SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + rib_queue_add(rn); + } + + nexthops_free(new_grp.nexthop); + + return (found ? 0 : -1); } int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, @@ -2889,7 +2903,12 @@ 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; + struct nexthop_group new_grp = {}; + struct nhg_hash_entry *nhe = NULL; + + nexthop_group_copy(&new_grp, re->ng); + + for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { if (nexthop->nh_label_type != lsp_type) continue; @@ -2900,6 +2919,15 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, ROUTE_ENTRY_LABELS_CHANGED); update = 1; } + + if (CHECK_FLAG(re->status, + ROUTE_ENTRY_LABELS_CHANGED)) { + nhe = zebra_nhg_rib_find(0, &new_grp, + re->vrf_id, afi); + zebra_nhg_re_update_ref(re, nhe); + } + + nexthops_free(new_grp.nexthop); } if (update) From 6df591527f8de78378e24096de6e78f42797b737 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 15:58:02 -0700 Subject: [PATCH 107/189] 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(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 429d4c59a1a2..239988b3abd9 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 8fe673cb3186..0258c240906e 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)) From 055a3fa698319845cc6f30376db90411f6b7be24 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:06:19 -0700 Subject: [PATCH 108/189] zebra: Check group before setting NHE invalid If the nhg_hash_entry is a group, check if its members are valid before setting it invalid. If even one is valid, then this group should still be considered valid. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3ceb5e33862e..d9930ae193db 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -889,9 +889,21 @@ bool zebra_nhg_id_is_valid(uint32_t id) return is_valid; } - void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) { + if (!zebra_nhg_depends_is_empty(nhe) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) { + struct nhg_connected *rb_node_dep = NULL; + + /* If anthing else in the group is valid, the group is valid */ + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_dependents) { + if (CHECK_FLAG(rb_node_dep->nhe->flags, + NEXTHOP_GROUP_VALID)) + return; + } + } + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); /* Assuming uninstalled as well here */ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); From 9ddc33505af6ad1fd99cd23352fc2dc99462afbb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:11:00 -0700 Subject: [PATCH 109/189] zebra: Remove uneeded is_valid NHE functons Remove some unused is_valid checks for the nhg_hash_entry's. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 20 -------------------- zebra/zebra_nhg.h | 1 - 2 files changed, 21 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index d9930ae193db..26db14036e41 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -869,26 +869,6 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) } } -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) { if (!zebra_nhg_depends_is_empty(nhe) diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index ef8b2730fbf1..31a2a020a020 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -223,7 +223,6 @@ void zebra_nhg_free(void *arg); 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); From 5155d86c6f8752dc9bdfeb9552f7f06c02567e17 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 14 May 2019 16:12:53 -0700 Subject: [PATCH 110/189] zebra: Ignore cleanup for now Ignore the cleanup for now until we get the timing figured out without using the kernel nexthop object API. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 26db14036e41..2d9ed8f69f6b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1664,6 +1664,9 @@ static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) */ void zebra_nhg_cleanup_tables(void) { + // TODO: These should only be uninstalled via route cleanup + // path? + return; hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL); } From 2d3c57e671d713feb7a6ef34982c375616368dc6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 15 May 2019 09:59:37 -0700 Subject: [PATCH 111/189] zebra: NHG checkpatch fixes Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 12 ++-- zebra/zebra_nhg.c | 143 +++++-------------------------------------- zebra/zebra_vty.c | 1 + 3 files changed, 23 insertions(+), 133 deletions(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 239988b3abd9..f1a099bb5222 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1593,8 +1593,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, 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 */ zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; if (!zns->supports_nh) { @@ -1602,8 +1600,10 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, goto done; } - // TODO: Might not need to mark this as an update, since - // it probably won't require two messages + /* + * TODO: Might not need to mark this as an update, since + * it probably won't require two messages + */ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE)); ret = AOK; @@ -1886,9 +1886,9 @@ dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) } ret = dplane_ctx_nexthop_init(ctx, op, nhe); - if (ret == AOK) { + if (ret == AOK) ret = dplane_update_enqueue(ctx); - } + done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2d9ed8f69f6b..ebe507a73c5a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -175,35 +175,18 @@ bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) return nhg_connected_head_is_empty(&nhe->nhg_depends); } -/** - * 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 - */ void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend) { nhg_connected_head_del(&from->nhg_depends, depend); } -/** - * zebra_nhg_depends_add() - Add a new dependency to the nhg_hash_entry - * - * @to: Nexthop group hash entry we are adding to - * @depend: Dependency we are adding - */ void zebra_nhg_depends_add(struct nhg_hash_entry *to, struct nhg_hash_entry *depend) { nhg_connected_head_add(&to->nhg_depends, depend); } -/** - * zebra_nhg_depends_init() - Initialize tree for nhg dependencies - * - * @nhe: Nexthop group hash entry - */ void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) { nhg_connected_head_init(&nhe->nhg_depends); @@ -233,35 +216,18 @@ 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); @@ -281,13 +247,6 @@ static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe) } } -/** - * 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 = {}; @@ -296,13 +255,6 @@ struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t 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)) { @@ -424,19 +376,6 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -/** - * nhg_connected cmp() - Compare the ID's of two connected nhg's - * - * @con1: Connected group entry #1 - * @con2: Connected group entry #2 - * - * Return: - * - Negative: #1 < #2 - * - Positive: #1 > #2 - * - Zero: #1 = #2 - * - * This is used in the nhg RB trees. - */ static int nhg_connected_cmp(const struct nhg_connected *con1, const struct nhg_connected *con2) { @@ -596,7 +535,8 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) if (nhe) { if (ctx->id != nhe->id) /* Duplicate but with different ID from - * the kernel */ + * the kernel + */ /* The kernel allows duplicate nexthops * as long as they have different IDs. @@ -731,13 +671,13 @@ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, struct nhg_hash_entry *depend = NULL; struct nhg_connected_head nhg_depends = {}; - // Defualt the nhe to the afi and vrf of the route + /* 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 (!nhg) { flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, - "No nexthop passed to zebra_nhg_rib_find()"); + "No nexthop passed to %s", __func__); return NULL; } @@ -773,13 +713,6 @@ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, return nhe; } -/** - * zebra_nhg_free_members() - Free all members in the hash entry struct - * - * @nhe: Nexthop group hash entry - * - * Just use this to free everything but the entry itself. - */ void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { nexthop_group_free_delete(&nhe->nhg); @@ -787,11 +720,6 @@ void zebra_nhg_free_members(struct nhg_hash_entry *nhe) nhg_connected_head_free(&nhe->nhg_dependents); } -/** - * 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 *nhe = NULL; @@ -803,11 +731,6 @@ void zebra_nhg_free(void *arg) XFREE(MTYPE_NHG, nhe); } -/** - * zebra_nhg_release() - Release a nhe from the tables - * - * @nhe: Nexthop group hash entry - */ static void zebra_nhg_release(struct nhg_hash_entry *nhe) { zlog_debug("Releasing nexthop group with ID (%u)", nhe->id); @@ -824,14 +747,6 @@ static void zebra_nhg_release(struct nhg_hash_entry *nhe) zebra_nhg_free(nhe); } -/** - * 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--; @@ -850,11 +765,6 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) zebra_nhg_uninstall_kernel(nhe); } -/** - * zebra_nhg_increment_ref() - Increment the reference count - * - * @nhe: Nexthop group hash entry - */ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) { nhe->refcnt++; @@ -1081,13 +991,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (connected_is_unnumbered(ifp)) { if (if_is_operative(ifp)) return 1; - else { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "\t%s: Onlink and interface %s is not operative", - __PRETTY_FUNCTION__, ifp->name); - return 0; - } + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "\t%s: Onlink and interface %s is not operative", + __PRETTY_FUNCTION__, ifp->name); + return 0; } if (!if_is_operative(ifp)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) @@ -1147,7 +1056,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, /* Pick up selected route. */ /* However, do not resolve over default route unless explicitly - * allowed. */ + * allowed. + */ if (is_default_prefix(&rn->p) && !rnh_resolve_via_default(zvrf, p.family)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) @@ -1165,7 +1075,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, match = dest->selected_fib; /* If there is no selected route or matched route is EGP, go up - tree. */ + * tree. + */ if (!match) { do { rn = rn->parent; @@ -1587,17 +1498,13 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) return i; } -/** - * zebra_nhg_install_kernel() - Install Nexthop Group hash entry into kernel - * - * @nhe: Nexthop Group hash entry to install - */ 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) { case ZEBRA_DPLANE_REQUEST_QUEUED: SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); @@ -1615,15 +1522,11 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) } } -/** - * zebra_nhg_uninstall_kernel() - Uninstall Nexthop Group hash entry into kernel - * - * @nhe: Nexthop Group hash entry to uninstall - */ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) { if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { int ret = dplane_nexthop_delete(nhe); + switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); @@ -1643,11 +1546,6 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) zebra_nhg_release(nhe); } -/** - * zebra_nhg_uninstall_created() - Uninstall nexthops we created in the kernel - * - * @nhe: Nexthop group hash entry - */ static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) { struct nhg_hash_entry *nhe = NULL; @@ -1658,10 +1556,6 @@ static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) zebra_nhg_uninstall_kernel(nhe); } -/** - * zebra_nhg_cleanup_tables() - Iterate over our tables to uninstall nh's - * we created - */ void zebra_nhg_cleanup_tables(void) { // TODO: These should only be uninstalled via route cleanup @@ -1670,11 +1564,6 @@ void zebra_nhg_cleanup_tables(void) hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL); } -/** - * zebra_nhg_dplane_result() - Process dplane result - * - * @ctx: Dataplane context - */ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) { enum dplane_op_e op; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index cd099da37e9d..fa20b07c1574 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1166,6 +1166,7 @@ DEFPY (show_nexthop_group, { afi_t afi = 0; + if (v4) afi = AFI_IP; else if (v6) From 1e9aad82ba65df9c50eb819334cb2caace57df6c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 15 May 2019 21:24:43 -0700 Subject: [PATCH 112/189] zebra: Add cli show NHE by ID and interface groups Add cli to show nhg_hash_entry's by ID. Add cli to show nhg_hash_entry info for interfaces and remove just listing ID's in `show interface *` Signed-off-by: Stephen Worley --- zebra/interface.c | 17 ----- zebra/zebra_vty.c | 154 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 117 insertions(+), 54 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 94f5cb58cd65..2cfceaa6d99c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1220,12 +1220,6 @@ static void nbr_connected_dump_vty(struct vty *vty, vty_out(vty, "\n"); } -static void nhg_dependent_dump_vty(struct vty *vty, - struct nhg_connected *connected) -{ - vty_out(vty, " (%u)", connected->nhe->id); -} - static const char *zebra_ziftype_2str(zebra_iftype_t zif_type) { switch (zif_type) { @@ -1458,17 +1452,6 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) connected_dump_vty(vty, connected); } - if (!if_nhg_dependents_is_empty(ifp)) { - struct nhg_connected *rb_node_dep = NULL; - - vty_out(vty, " Nexthop IDs 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"); - } - vty_out(vty, " Interface Type %s\n", zebra_ziftype_2str(zebra_if->zif_type)); if (IS_ZEBRA_IF_BRIDGE(ifp)) { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index fa20b07c1574..45515e30c0e9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -53,6 +53,7 @@ #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_pbr.h" #include "zebra/zebra_nhg.h" +#include "zebra/interface.h" extern int allow_delete; @@ -1102,16 +1103,69 @@ DEFUN (ip_nht_default_route, return CMD_SUCCESS; } +static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) +{ + struct nexthop *nhop = NULL; + struct nhg_connected *rb_node_dep = NULL; + + vty_out(vty, "ID: %u\n", nhe->id); + vty_out(vty, "\tRefCnt: %d\n", nhe->refcnt); + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { + vty_out(vty, "\tValid"); + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) + vty_out(vty, ", Installed"); + vty_out(vty, "\n"); + } + if (nhe->ifp) + vty_out(vty, "\tInterface Index: %d\n", nhe->ifp->ifindex); + + if (!zebra_nhg_depends_is_empty(nhe)) { + + vty_out(vty, "\tDepends:"); + RB_FOREACH (rb_node_dep, nhg_connected_head, + &nhe->nhg_depends) { + vty_out(vty, " (%u)", rb_node_dep->nhe->id); + } + vty_out(vty, "\n"); + } + if (!zebra_nhg_dependents_is_empty(nhe)) { + 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)) { + vty_out(vty, "\t"); + nexthop_group_write_nexthop(vty, nhop); + } +} + +static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id) +{ + struct nhg_hash_entry *nhe = NULL; + + nhe = zebra_nhg_lookup_id(id); + + if (nhe) + show_nexthop_group_out(vty, nhe); + else { + vty_out(vty, "Nexthop Group ID: %u does not exist\n", id); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + static void show_nexthop_group_cmd_helper(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi) { struct list *list = hash_to_list(zrouter.nhgs); - struct nhg_hash_entry *nhe; - struct listnode *node; + struct nhg_hash_entry *nhe = NULL; + struct listnode *node = NULL; for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) { - struct nexthop *nhop; - struct nhg_connected *rb_node_dep = NULL; if (afi && nhe->afi != afi) continue; @@ -1119,61 +1173,86 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, if (nhe->vrf_id != zvrf->vrf->vrf_id) continue; - vty_out(vty, "Group: %u ID: %u\n", nhe->dplane_ref, nhe->id); - vty_out(vty, "\tRefCnt: %d\n", nhe->refcnt); - 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); - - if (!zebra_nhg_depends_is_empty(nhe)) { - - vty_out(vty, "\tDepends:"); - RB_FOREACH (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends) { - vty_out(vty, " (%u)", rb_node_dep->nhe->id); - } - vty_out(vty, "\n"); + show_nexthop_group_out(vty, nhe); + } - } 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"); + list_delete(&list); +} + +static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp) +{ + struct zebra_if *zebra_if = NULL; + struct nhg_connected *rb_node_dep = NULL; + + zebra_if = ifp->info; + + if (!if_nhg_dependents_is_empty(ifp)) { + vty_out(vty, "Interface %s:\n", ifp->name); + + RB_FOREACH (rb_node_dep, nhg_connected_head, + &zebra_if->nhg_dependents) { + vty_out(vty, " "); + show_nexthop_group_out(vty, rb_node_dep->nhe); } + } +} - for (ALL_NEXTHOPS_PTR(nhe->nhg, nhop)) { - vty_out(vty, "\t"); - nexthop_group_write_nexthop(vty, nhop); +DEFPY (show_interface_nexthop_group, + show_interface_nexthop_group_cmd, + "show interface [IFNAME$if_name] nexthop-group", + SHOW_STR + "Interface status and configuration\n" + "Interface name\n" + "Show Nexthop Groups\n") +{ + struct vrf *vrf = NULL; + struct interface *ifp = NULL; + bool found = false; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (if_name) { + ifp = if_lookup_by_name(if_name, vrf->vrf_id); + if (ifp) { + if_nexthop_group_dump_vty(vty, ifp); + found = true; + } + } else { + FOR_ALL_INTERFACES (vrf, ifp) + if_nexthop_group_dump_vty(vty, ifp); + found = true; } } - list_delete(&list); + if (!found) { + vty_out(vty, "%% Can't find interface %s\n", if_name); + return CMD_WARNING; + } + + return CMD_SUCCESS; } DEFPY (show_nexthop_group, show_nexthop_group_cmd, - "show nexthop-group [] [vrf ]", + "show nexthop-group <(0-4294967295)$id|[] [vrf ]>", SHOW_STR + "Show Nexthop Groups\n" + "Nexthop Group ID\n" IP_STR IP6_STR - "Show Nexthop Groups\n" VRF_FULL_CMD_HELP_STR) { + struct zebra_vrf *zvrf = NULL; afi_t afi = 0; + if (id) + return show_nexthop_group_id_cmd_helper(vty, id); + if (v4) afi = AFI_IP; else if (v6) afi = AFI_IP6; - struct zebra_vrf *zvrf; - if (vrf_all) { struct vrf *vrf; @@ -1198,7 +1277,7 @@ DEFPY (show_nexthop_group, if (!zvrf) { vty_out(vty, "VRF %s specified does not exist", vrf_name); - return CMD_SUCCESS; + return CMD_WARNING; } show_nexthop_group_cmd_helper(vty, zvrf, afi); @@ -3139,6 +3218,7 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &no_zebra_packet_process_cmd); install_element(VIEW_NODE, &show_nexthop_group_cmd); + install_element(VIEW_NODE, &show_interface_nexthop_group_cmd); install_element(VIEW_NODE, &show_vrf_cmd); install_element(VIEW_NODE, &show_vrf_vni_cmd); From 9834bb52aebb46fc4ba85e959cc98adda996a4b3 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 2 Jul 2019 01:04:29 -0400 Subject: [PATCH 113/189] zebra: Resolved nh change, inc refcnt by rt refcnt When the resolved nexthop changes, we should increment the new resolved NHE by the refcnt for the unresolved NHE being used by the routes and decrement the old one by the same amount. Before, we were simple incrementing by one, causing incorrect refcnts to occur. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ebe507a73c5a..436783065d7f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1364,13 +1364,12 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) /* 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); + + if (old_resolved && new_resolved->id != old_resolved->id) { + new_resolved->refcnt+=nhe->refcnt; + old_resolved->refcnt-=nhe->refcnt; + } else if (!old_resolved) + zebra_nhg_increment_ref(new_resolved); SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); } else From 139ddad8f12cf6dbf2993af196cc33476c2b79cf Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 2 Jul 2019 01:07:59 -0400 Subject: [PATCH 114/189] zebra: Accept NULL value for updating route NHE When updating a route's referenced NHE, accept a NULL value as valid and clear out the pointer in the struct. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 436783065d7f..04a11dfcb659 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1447,9 +1447,12 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) { struct nhg_hash_entry *old = NULL; + int ret = 0; - if (!new) - return -1; + if (new == NULL) { + re->ng = NULL; + goto done; + } if (re->nhe_id != new->id) { old = zebra_nhg_lookup_id(re->nhe_id); @@ -1462,7 +1465,8 @@ int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) zebra_nhg_decrement_ref(old); } - return 0; +done: + return ret; } /* Convert a nhe into a group array */ From 7f997721693c63afcdf1d23f7449f8acbbe282d1 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 2 Jul 2019 01:16:48 -0400 Subject: [PATCH 115/189] 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(-) diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index cbbb02be35d2..42d8c70f4911 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 04a11dfcb659..8592e6500d2e 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 31a2a020a020..ff2c73433aa2 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 0258c240906e..6be91da54aa9 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, From 2f00094498ebd5dc65c66c1219e4553e36ec35f6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 2 Jul 2019 01:34:57 -0400 Subject: [PATCH 116/189] lib: Hash on resolved nexthops by default Include resolved nexthops when hashing a nexthop group but provide an API that allows you to non-recursively hash as well. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 13 ++++++++++++- lib/nexthop_group.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index c9a8f1af5102..a79b2741c548 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -273,7 +273,7 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, } } -uint32_t nexthop_group_hash(const struct nexthop_group *nhg) +uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg) { struct nexthop *nh; uint32_t key = 0; @@ -288,6 +288,17 @@ uint32_t nexthop_group_hash(const struct nexthop_group *nhg) return key; } +uint32_t nexthop_group_hash(const struct nexthop_group *nhg) +{ + struct nexthop *nh; + uint32_t key = 0; + + for (ALL_NEXTHOPS_PTR(nhg, nh)) + key = jhash_1word(nexthop_hash(nh), key); + + return key; +} + 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 57a5a975993e..a765b4b76b13 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -48,6 +48,7 @@ void nexthop_group_copy(struct nexthop_group *to, void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, struct nexthop *rparent); +uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg); uint32_t nexthop_group_hash(const struct nexthop_group *nhg); /* The following for loop allows to iterate over the nexthop From df31a989cac681c061051bbd6f53d8a246f41135 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 2 Jul 2019 01:37:17 -0400 Subject: [PATCH 117/189] zebra: Refactor nexthop resolution in active funcs Refactor/move around the code for nexthop resolution so that it occurs only when the nexthop actually changes. Further, provide a helper function to make the code more readable. Also, remove the check for NEXTHOPS_CHANGED as this flag is used specifcially for nexthop tracking and not an appropriate check here. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 141 +++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 65 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 8592e6500d2e..1b6e83178079 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -918,6 +918,48 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop, return true; } +static bool zebra_nhg_set_resolved(struct nhg_hash_entry *nhe, + struct nhg_hash_entry *resolved) +{ + bool new = true; + struct nhg_hash_entry *old_resolved = NULL; + struct nexthop *nh = NULL; + + assert(!CHECK_FLAG(resolved->flags, NEXTHOP_GROUP_RECURSIVE)); + + /* 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); + + /* Add new resolved */ + zebra_nhg_depends_add(nhe, resolved); + zebra_nhg_dependents_add(resolved, nhe); + + if (old_resolved && resolved->id != old_resolved->id) { + resolved->refcnt += nhe->refcnt; + old_resolved->refcnt -= nhe->refcnt; + } else if (!old_resolved) + zebra_nhg_increment_ref(resolved); + else + new = false; /* Same one that was there */ + + for (nh = resolved->nhg->nexthop; nh; nh = nh->next) + nexthop_set_resolved(nhe->afi, nhe->nhg->nexthop, nh); + + SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); + + return new; +} + + /* * Given a nexthop we need to properly recursively resolve * the route. As such, do a table lookup to find and match @@ -926,7 +968,7 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop, */ static int nexthop_active(afi_t afi, struct route_entry *re, struct nexthop *nexthop, struct route_node *top, - uint32_t *resolved_id) + struct nhg_hash_entry **resolved_nhe) { struct prefix p; struct route_table *table; @@ -1102,7 +1144,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } if (resolved) { re->nexthop_mtu = match->mtu; - *resolved_id = match->nhe_id; + zebra_nhg_find_nexthop(resolved_nhe, 0, + nexthop->resolved, afi, + false); } if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("\t%s: Recursion failed to find", @@ -1124,7 +1168,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } if (resolved) { re->nexthop_mtu = match->mtu; - *resolved_id = match->nhe_id; + zebra_nhg_find_nexthop(resolved_nhe, 0, + nexthop->resolved, afi, + false); } if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( @@ -1165,7 +1211,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, static unsigned nexthop_active_check(struct route_node *rn, struct route_entry *re, struct nexthop *nexthop, - uint32_t *resolved_id) + struct nhg_hash_entry **resolved_nhe) { struct interface *ifp; route_map_result_t ret = RMAP_PERMITMATCH; @@ -1193,14 +1239,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, resolved_id)) + if (nexthop_active(AFI_IP, re, nexthop, rn, resolved_nhe)) 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, resolved_id)) + if (nexthop_active(AFI_IP6, re, nexthop, rn, resolved_nhe)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -1218,7 +1264,7 @@ static unsigned nexthop_active_check(struct route_node *rn, UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } else { if (nexthop_active(AFI_IP6, re, nexthop, rn, - resolved_id)) + resolved_nhe)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -1298,6 +1344,7 @@ 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; + bool new_resolve = false; afi_t rt_afi = family2afi(rn->p.family); @@ -1308,7 +1355,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { struct nhg_hash_entry *nhe = NULL; - uint32_t resolved_id = 0; + struct nhg_hash_entry *resolved_nhe = NULL; /* No protocol daemon provides src and so we're skipping * tracking it */ @@ -1322,52 +1369,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) * decision point. */ 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); - - if (old_resolved && new_resolved->id != old_resolved->id) { - new_resolved->refcnt+=nhe->refcnt; - old_resolved->refcnt-=nhe->refcnt; - } else if (!old_resolved) - zebra_nhg_increment_ref(new_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); - } + nexthop_active_check(rn, re, nexthop, &resolved_nhe); if (new_active && nexthop_group_active_nexthop_num(&new_grp) @@ -1376,15 +1378,9 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) new_active = 0; } - if (nhe && new_active) { + if (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 @@ -1395,11 +1391,26 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) && nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && !(IPV6_ADDR_SAME(&prev_src.ipv6, &nexthop->rmap_src.ipv6))) - || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) + || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) { SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + + /* + * Create the individual nexthop hash entries + * for the nexthops in the group + */ + + nhe = depends_find(nexthop, rt_afi); + + if (resolved_nhe) + new_resolve = zebra_nhg_set_resolved( + nhe, resolved_nhe); + + if (nhe && new_active) + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + } } - if (CHECK_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) || new_resolve) { struct nhg_hash_entry *new_nhe = NULL; // TODO: Add proto type here @@ -1477,8 +1488,8 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) 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); + "Failed to recursively resolve Nexthop Hash Entry in the group id=%u", + nhe->id); continue; } } From 8a507796fc37fefdc76cea7a73a3972a7ee945bb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 3 Jul 2019 16:09:20 +0000 Subject: [PATCH 118/189] zebra: Set resolved nhg in find path Set the resolved nhg during the find path, rather than after it has been created. This make more sense now that we are hashing on the resolved nexthop as well. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 138 ++++++++++++++++------------------------------ 1 file changed, 49 insertions(+), 89 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1b6e83178079..443b0198280b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -48,6 +48,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context"); static int nhg_connected_cmp(const struct nhg_connected *dep1, const struct nhg_connected *dep2); +static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi); RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); @@ -471,11 +472,30 @@ static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id, bool is_kernel_nh) { struct nexthop_group nhg = {}; + struct nhg_connected_head nhg_depends = {}; + bool created = true; _nexthop_group_add_sorted(&nhg, nh); - return zebra_nhg_find(nhe, id, &nhg, NULL, nh->vrf_id, afi, - is_kernel_nh); + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { + struct nhg_hash_entry *depend = NULL; + + nhg_connected_head_init(&nhg_depends); + + depend = depends_find(nh->resolved, afi); + nhg_connected_head_add(&nhg_depends, depend); + } + + if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, + is_kernel_nh)) { + created = false; + nhg_connected_head_free(&nhg_depends); + } else { + if (zebra_nhg_depends_count(*nhe)) + SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE); + } + + return created; } static struct nhg_ctx *nhg_ctx_new() @@ -650,14 +670,20 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) { - struct nexthop lookup = {0}; + struct nexthop *lookup = NULL; struct nhg_hash_entry *nhe = NULL; - lookup = *nh; + copy_nexthops(&lookup, nh, NULL); + /* Clear it, in case its a group */ - lookup.next = NULL; - lookup.prev = NULL; - zebra_nhg_find_nexthop(&nhe, 0, &lookup, afi, false); + nexthops_free(lookup->next); + nexthops_free(lookup->prev); + lookup->next = NULL; + lookup->prev = NULL; + + zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, false); + + nexthops_free(lookup); return nhe; } @@ -731,7 +757,8 @@ 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); + if(!hash_release(zrouter.nhgs, nhe)) + zlog_debug("Failed release"); hash_release(zrouter.nhgs_id, nhe); zebra_nhg_free(nhe); @@ -918,48 +945,6 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop, return true; } -static bool zebra_nhg_set_resolved(struct nhg_hash_entry *nhe, - struct nhg_hash_entry *resolved) -{ - bool new = true; - struct nhg_hash_entry *old_resolved = NULL; - struct nexthop *nh = NULL; - - assert(!CHECK_FLAG(resolved->flags, NEXTHOP_GROUP_RECURSIVE)); - - /* 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); - - /* Add new resolved */ - zebra_nhg_depends_add(nhe, resolved); - zebra_nhg_dependents_add(resolved, nhe); - - if (old_resolved && resolved->id != old_resolved->id) { - resolved->refcnt += nhe->refcnt; - old_resolved->refcnt -= nhe->refcnt; - } else if (!old_resolved) - zebra_nhg_increment_ref(resolved); - else - new = false; /* Same one that was there */ - - for (nh = resolved->nhg->nexthop; nh; nh = nh->next) - nexthop_set_resolved(nhe->afi, nhe->nhg->nexthop, nh); - - SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); - - return new; -} - - /* * Given a nexthop we need to properly recursively resolve * the route. As such, do a table lookup to find and match @@ -967,8 +952,7 @@ static bool zebra_nhg_set_resolved(struct nhg_hash_entry *nhe, * as appropriate */ static int nexthop_active(afi_t afi, struct route_entry *re, - struct nexthop *nexthop, struct route_node *top, - struct nhg_hash_entry **resolved_nhe) + struct nexthop *nexthop, struct route_node *top) { struct prefix p; struct route_table *table; @@ -984,6 +968,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, || nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = 0; + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; @@ -1142,12 +1127,9 @@ 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; - zebra_nhg_find_nexthop(resolved_nhe, 0, - nexthop->resolved, afi, - false); - } + if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("\t%s: Recursion failed to find", __PRETTY_FUNCTION__); @@ -1166,12 +1148,9 @@ 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; - zebra_nhg_find_nexthop(resolved_nhe, 0, - nexthop->resolved, afi, - false); - } + if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "\t%s: Static route unable to resolve", @@ -1210,8 +1189,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, */ static unsigned nexthop_active_check(struct route_node *rn, struct route_entry *re, - struct nexthop *nexthop, - struct nhg_hash_entry **resolved_nhe) + struct nexthop *nexthop) { struct interface *ifp; route_map_result_t ret = RMAP_PERMITMATCH; @@ -1239,14 +1217,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, resolved_nhe)) + if (nexthop_active(AFI_IP, re, nexthop, rn)) 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, resolved_nhe)) + if (nexthop_active(AFI_IP6, re, nexthop, rn)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -1263,8 +1241,7 @@ 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, - resolved_nhe)) + if (nexthop_active(AFI_IP6, re, nexthop, rn)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -1344,7 +1321,6 @@ 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; - bool new_resolve = false; afi_t rt_afi = family2afi(rn->p.family); @@ -1354,8 +1330,6 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) nexthop_group_copy(&new_grp, re->ng); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { - struct nhg_hash_entry *nhe = NULL; - struct nhg_hash_entry *resolved_nhe = NULL; /* No protocol daemon provides src and so we're skipping * tracking it */ @@ -1369,7 +1343,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) * decision point. */ new_active = - nexthop_active_check(rn, re, nexthop, &resolved_nhe); + nexthop_active_check(rn, re, nexthop); if (new_active && nexthop_group_active_nexthop_num(&new_grp) @@ -1391,26 +1365,11 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) && nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && !(IPV6_ADDR_SAME(&prev_src.ipv6, &nexthop->rmap_src.ipv6))) - || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) { + || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - - /* - * Create the individual nexthop hash entries - * for the nexthops in the group - */ - - nhe = depends_find(nexthop, rt_afi); - - if (resolved_nhe) - new_resolve = zebra_nhg_set_resolved( - nhe, resolved_nhe); - - if (nhe && new_active) - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - } } - if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) || new_resolve) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { struct nhg_hash_entry *new_nhe = NULL; // TODO: Add proto type here @@ -1528,6 +1487,7 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) { + zlog_debug("Uninstalling NHE ID: %u", nhe->id); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { int ret = dplane_nexthop_delete(nhe); From a7df4ccf0ed9cc594b992dd34b5a740f44e9000f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 10 Jul 2019 20:11:47 +0000 Subject: [PATCH 119/189] lib: Hash nexthops on onlink flag We should hash nexthops on the onlink flag since that is a descriptor of the nexthop and not a status of it. Signed-off-by: Stephen Worley --- lib/nexthop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/nexthop.c b/lib/nexthop.c index cf5bed3d623a..e68e605a6f89 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -421,6 +421,9 @@ uint32_t nexthop_hash(const struct nexthop *nexthop) case NEXTHOP_TYPE_IPV6: break; } + + key = jhash_1word(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), key); + return key; } From 44d809a90b790dc5d3d9d292d6c7add00e4864b8 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Jul 2019 13:10:20 -0400 Subject: [PATCH 120/189] zebra: Remove nexthop group workqueue We are using the rib workqueue to handle nexthop groups from the kernel and no longer need this. Signed-off-by: Stephen Worley --- zebra/zebra_router.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 5a2f0c9fa154..497846e0fae4 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -106,11 +106,6 @@ struct zebra_router { #define ZEBRA_RIB_PROCESS_RETRY_TIME 1 struct work_queue *ribq; - /* The nexthop group work queue */ -#define ZEBRA_NHG_PROCESS_HOLD_TIME 1 -#define ZEBRA_NHG_PROCESS_RETRY_TIME 10 - struct work_queue *nhgq; - /* Meta Queue Information */ struct meta_queue *mq; From 32e29e79107a44caa97680c0ff8cad3f06385e13 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Jul 2019 13:15:51 -0400 Subject: [PATCH 121/189] zebra: Add nhg refcnt connected helper functions Add some helper functions for ref incrementing and decrementing the depends of a nexthop group hash entry. This just abstracts the RB tree manipulation a bit more. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 443b0198280b..cf579d7ba957 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -135,6 +135,25 @@ void nhg_connected_head_add(struct nhg_connected_head *head, RB_INSERT(nhg_connected_head, head, new); } +static void nhg_connected_head_decrement_ref(struct nhg_connected_head *head) +{ + struct nhg_connected *rb_node_dep = NULL; + struct nhg_connected *tmp = NULL; + + RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) { + zebra_nhg_decrement_ref(rb_node_dep->nhe); + } +} + +static void nhg_connected_head_increment_ref(struct nhg_connected_head *head) +{ + struct nhg_connected *rb_node_dep = NULL; + + RB_FOREACH (rb_node_dep, nhg_connected_head, head) { + zebra_nhg_increment_ref(rb_node_dep->nhe); + } +} + struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe) { if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE) @@ -768,15 +787,8 @@ 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; - struct nhg_connected *tmp = NULL; - - RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends, tmp) { - zebra_nhg_decrement_ref(rb_node_dep->nhe); - } - } + if (!zebra_nhg_depends_is_empty(nhe)) + nhg_connected_head_decrement_ref(&nhe->nhg_depends); if (!nhe->is_kernel_nh && nhe->refcnt <= 0) zebra_nhg_uninstall_kernel(nhe); @@ -786,14 +798,8 @@ 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; - - RB_FOREACH (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends) { - zebra_nhg_increment_ref(rb_node_dep->nhe); - } - } + if (!zebra_nhg_depends_is_empty(nhe)) + nhg_connected_head_increment_ref(&nhe->nhg_depends); } void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) From 5657e7e943f517a252099ccde9c2273530e97584 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Jul 2019 13:19:56 -0400 Subject: [PATCH 122/189] zebra: Add some depends helper functions Add some helper functions for finding/creating nexthop group hash entries and assigning them as a depends for another one using them in a group or resolving to them. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index cf579d7ba957..8fc61113ec41 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -49,6 +49,11 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context"); static int nhg_connected_cmp(const struct nhg_connected *dep1, const struct nhg_connected *dep2); static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi); +static void depends_add(struct nhg_connected_head *head, + struct nhg_hash_entry *depend); +static void depends_find_add(struct nhg_connected_head *head, + struct nexthop *nh, afi_t afi); +static void depends_decrement_free(struct nhg_connected_head *head); RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); @@ -485,6 +490,18 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, return created; } +static void handle_recursive_depend(struct nhg_connected_head *nhg_depends, + struct nexthop *nh, afi_t afi) +{ + struct nhg_hash_entry *depend = NULL; + struct nexthop_group resolved_ng = {}; + + _nexthop_group_add_sorted(&resolved_ng, nh); + + depend = zebra_nhg_rib_find(0, &resolved_ng, afi); + depends_add(nhg_depends, depend); +} + /* 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, @@ -687,6 +704,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, return 0; } +/* Some dependency helper functions */ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) { struct nexthop *lookup = NULL; @@ -707,6 +725,28 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) return nhe; } +static void depends_add(struct nhg_connected_head *head, + struct nhg_hash_entry *depend) +{ + nhg_connected_head_add(head, depend); + zebra_nhg_increment_ref(depend); +} + +static void depends_find_add(struct nhg_connected_head *head, + struct nexthop *nh, afi_t afi) +{ + struct nhg_hash_entry *depend = NULL; + + depend = depends_find(nh, afi); + depends_add(head, depend); +} + +static void depends_decrement_free(struct nhg_connected_head *head) +{ + nhg_connected_head_decrement_ref(head); + nhg_connected_head_free(head); +} + /* Rib-side, you get a nexthop group struct */ struct nhg_hash_entry * zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) From 583965448f2bac1e2f8b6e6fed7aee25bda1fe88 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Jul 2019 13:22:23 -0400 Subject: [PATCH 123/189] zebra: Add refcnt for depends when connected Add a refcnt as soon as depend is connected to mark that this is being referenced as part of a group or resolving another one. If the one referencing it is never used, decrement it. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 8fc61113ec41..9a4c08be7e05 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -514,18 +514,14 @@ static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id, _nexthop_group_add_sorted(&nhg, nh); if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { - struct nhg_hash_entry *depend = NULL; - nhg_connected_head_init(&nhg_depends); - - depend = depends_find(nh->resolved, afi); - nhg_connected_head_add(&nhg_depends, depend); + handle_recursive_depend(&nhg_depends, nh->resolved, afi); } if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, is_kernel_nh)) { created = false; - nhg_connected_head_free(&nhg_depends); + depends_decrement_free(&nhg_depends); } else { if (zebra_nhg_depends_count(*nhe)) SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE); @@ -752,7 +748,6 @@ 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; struct nhg_connected_head nhg_depends = {}; /* Defualt the nhe to the afi and vrf of the route */ @@ -771,10 +766,8 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) /* 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); - } + for (nh = nhg->nexthop; nh; nh = nh->next) + depends_find_add(&nhg_depends, nh, rt_afi); /* change the afi/vrf_id since its a group */ nhg_afi = AFI_UNSPEC; @@ -783,7 +776,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)) - nhg_connected_head_free(&nhg_depends); + depends_decrement_free(&nhg_depends); return nhe; } @@ -791,6 +784,8 @@ 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); + /* Decrement to remove connection ref */ + nhg_connected_head_decrement_ref(&nhe->nhg_depends); nhg_connected_head_free(&nhe->nhg_depends); nhg_connected_head_free(&nhe->nhg_dependents); } From 360aefc01854e9d4bb4163e85adc82354817ecdb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Jul 2019 13:26:19 -0400 Subject: [PATCH 124/189] zebra: zebra_nhg_rib_find() handle recursive case When going through the zebra_nhg_rib_find(), we now handle the case of if that nexthop has been recursively resolved. A depend is created and passed along to zebra_nhg_find(). Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9a4c08be7e05..15367b27428a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -772,6 +772,10 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) /* change the afi/vrf_id since its a group */ nhg_afi = AFI_UNSPEC; nhg_vrf_id = 0; + } else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { + nhg_connected_head_init(&nhg_depends); + handle_recursive_depend(&nhg_depends, nhg->nexthop->resolved, + rt_afi); } if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, From 6e3af3f17a5f1000822b0a5726920ab4a8c82968 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 24 Jul 2019 12:02:16 -0400 Subject: [PATCH 125/189] zebra: Set recursive flag in rib_find() path We were not setting the NEXTHOP_GROUP_RECURSIVE flag via the rib find path. Adding a check and set after successful creation of a new nhg_hash_entry. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 15367b27428a..e17ddffec3de 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -781,6 +781,8 @@ 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)) depends_decrement_free(&nhg_depends); + else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); return nhe; } From 8654a42cd5f96ac6185997e5a3c63f1c69c40a75 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 17 Jul 2019 13:56:59 -0400 Subject: [PATCH 126/189] zebra: Remove some extraneous zebra_nhg logging Remove some extraneos zebra_nhg logging that was being used during development. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index e17ddffec3de..3c21319f992b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -809,16 +809,13 @@ void zebra_nhg_free(void *arg) static void zebra_nhg_release(struct nhg_hash_entry *nhe) { - zlog_debug("Releasing nexthop group with ID (%u)", nhe->id); - /* Remove it from any lists it may be on */ zebra_nhg_depends_release(nhe); zebra_nhg_dependents_release(nhe); if (nhe->ifp) if_nhg_dependents_del(nhe->ifp, nhe); - if(!hash_release(zrouter.nhgs, nhe)) - zlog_debug("Failed release"); + hash_release(zrouter.nhgs, nhe); hash_release(zrouter.nhgs_id, nhe); zebra_nhg_free(nhe); @@ -1534,7 +1531,6 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) { - zlog_debug("Uninstalling NHE ID: %u", nhe->id); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { int ret = dplane_nexthop_delete(nhe); From 37c6708b93af52a4f0e271d217ba973a683ed71f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 24 Jul 2019 12:27:40 -0400 Subject: [PATCH 127/189] zebra: Switch nhg_connected to use new RB tree Switch the nhg_connected tree structures to use the new RB tree API in `lib/typerb.h`. We were using the openbsd-tree implementation before. Signed-off-by: Stephen Worley --- zebra/interface.c | 20 +++--- zebra/interface.h | 2 +- zebra/zebra_nhg.c | 167 +++++++++++++++++++--------------------------- zebra/zebra_nhg.h | 33 +++++---- zebra/zebra_vty.c | 11 ++- 5 files changed, 105 insertions(+), 128 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 2cfceaa6d99c..4754762b979c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -109,12 +109,12 @@ static void zebra_if_node_destroy(route_table_delegate_t *delegate, static void zebra_if_nhg_dependents_free(struct zebra_if *zebra_if) { - nhg_connected_head_free(&zebra_if->nhg_dependents); + nhg_connected_tree_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); + nhg_connected_tree_init(&zebra_if->nhg_dependents); } @@ -195,8 +195,8 @@ 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; - RB_FOREACH (rb_node_dep, nhg_connected_head, - &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); } @@ -962,7 +962,7 @@ void if_nhg_dependents_add(struct interface *ifp, struct nhg_hash_entry *nhe) if (ifp->info) { struct zebra_if *zif = (struct zebra_if *)ifp->info; - nhg_connected_head_add(&zif->nhg_dependents, nhe); + nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe); } } @@ -971,7 +971,7 @@ 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; - nhg_connected_head_del(&zif->nhg_dependents, nhe); + nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe); } } @@ -980,7 +980,7 @@ unsigned int if_nhg_dependents_count(const struct interface *ifp) if (ifp->info) { struct zebra_if *zif = (struct zebra_if *)ifp->info; - return nhg_connected_head_count(&zif->nhg_dependents); + return nhg_connected_tree_count(&zif->nhg_dependents); } return 0; @@ -992,7 +992,7 @@ 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 nhg_connected_tree_is_empty(&zif->nhg_dependents); } return false; @@ -1004,8 +1004,8 @@ 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; - RB_FOREACH (rb_node_dep, nhg_connected_head, - &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/interface.h b/zebra/interface.h index d5c1e1713193..c6f0e465fcf1 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -285,7 +285,7 @@ struct zebra_if { * we will use this list to update the nexthops * pointing to it with that info. */ - struct nhg_connected_head nhg_dependents; + struct nhg_connected_tree_head nhg_dependents; /* Information about up/down changes */ unsigned int up_count; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3c21319f992b..13ea90254346 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -46,16 +46,12 @@ 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); static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi); -static void depends_add(struct nhg_connected_head *head, +static void depends_add(struct nhg_connected_tree_head *head, struct nhg_hash_entry *depend); -static void depends_find_add(struct nhg_connected_head *head, +static void depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, afi_t afi); -static void depends_decrement_free(struct nhg_connected_head *head); - -RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); +static void depends_decrement_free(struct nhg_connected_tree_head *head); void nhg_connected_free(struct nhg_connected *dep) @@ -73,48 +69,31 @@ struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) return new; } -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) +void nhg_connected_tree_free(struct nhg_connected_tree_head *head) { struct nhg_connected *rb_node_dep = NULL; - struct nhg_connected *tmp = NULL; - 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); + if (!nhg_connected_tree_is_empty(head)) { + frr_each_safe (nhg_connected_tree, head, rb_node_dep) { + nhg_connected_tree_del(head, rb_node_dep); nhg_connected_free(rb_node_dep); } } } -unsigned int nhg_connected_head_count(const struct nhg_connected_head *head) +bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head) { - struct nhg_connected *rb_node_dep = NULL; - unsigned int i = 0; - - RB_FOREACH (rb_node_dep, nhg_connected_head, head) { - i++; - } - return i; -} - -bool nhg_connected_head_is_empty(const struct nhg_connected_head *head) -{ - return RB_EMPTY(nhg_connected_head, head); + return (nhg_connected_tree_count(head) ? false : true); } struct nhg_connected * -nhg_connected_head_root(const struct nhg_connected_head *head) +nhg_connected_tree_root(struct nhg_connected_tree_head *head) { - return RB_ROOT(nhg_connected_head, head); + return nhg_connected_tree_first(head); } -void nhg_connected_head_del(struct nhg_connected_head *head, - struct nhg_hash_entry *depend) +void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head, + struct nhg_hash_entry *depend) { struct nhg_connected lookup = {}; struct nhg_connected *remove = NULL; @@ -122,39 +101,40 @@ void nhg_connected_head_del(struct nhg_connected_head *head, lookup.nhe = depend; /* Lookup to find the element, then remove it */ - remove = RB_FIND(nhg_connected_head, head, &lookup); - remove = RB_REMOVE(nhg_connected_head, head, remove); + remove = nhg_connected_tree_find(head, &lookup); + remove = nhg_connected_tree_del(head, remove); if (remove) nhg_connected_free(remove); } -void nhg_connected_head_add(struct nhg_connected_head *head, - struct nhg_hash_entry *depend) +void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head, + struct nhg_hash_entry *depend) { struct nhg_connected *new = NULL; new = nhg_connected_new(depend); if (new) - RB_INSERT(nhg_connected_head, head, new); + nhg_connected_tree_add(head, new); } -static void nhg_connected_head_decrement_ref(struct nhg_connected_head *head) +static void +nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head) { struct nhg_connected *rb_node_dep = NULL; - struct nhg_connected *tmp = NULL; - RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) { + frr_each_safe (nhg_connected_tree, head, rb_node_dep) { zebra_nhg_decrement_ref(rb_node_dep->nhe); } } -static void nhg_connected_head_increment_ref(struct nhg_connected_head *head) +static void +nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head) { struct nhg_connected *rb_node_dep = NULL; - RB_FOREACH (rb_node_dep, nhg_connected_head, head) { + frr_each (nhg_connected_tree, head, rb_node_dep) { zebra_nhg_increment_ref(rb_node_dep->nhe); } } @@ -163,7 +143,7 @@ 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; + nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe; return zebra_nhg_resolve(nhe); } @@ -192,29 +172,29 @@ uint32_t zebra_nhg_get_resolved_id(uint32_t id) unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe) { - return nhg_connected_head_count(&nhe->nhg_depends); + return nhg_connected_tree_count(&nhe->nhg_depends); } bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) { - return nhg_connected_head_is_empty(&nhe->nhg_depends); + return nhg_connected_tree_is_empty(&nhe->nhg_depends); } void zebra_nhg_depends_del(struct nhg_hash_entry *from, struct nhg_hash_entry *depend) { - nhg_connected_head_del(&from->nhg_depends, depend); + nhg_connected_tree_del_nhe(&from->nhg_depends, depend); } void zebra_nhg_depends_add(struct nhg_hash_entry *to, struct nhg_hash_entry *depend) { - nhg_connected_head_add(&to->nhg_depends, depend); + nhg_connected_tree_add_nhe(&to->nhg_depends, depend); } void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) { - nhg_connected_head_init(&nhe->nhg_depends); + nhg_connected_tree_init(&nhe->nhg_depends); } /* Release this nhe from anything that it depends on */ @@ -222,10 +202,9 @@ 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; - struct nhg_connected *tmp = NULL; - RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends, tmp) { + frr_each_safe (nhg_connected_tree, &nhe->nhg_depends, + rb_node_dep) { zebra_nhg_dependents_del(rb_node_dep->nhe, nhe); } } @@ -233,29 +212,29 @@ static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe) unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe) { - return nhg_connected_head_count(&nhe->nhg_dependents); + return nhg_connected_tree_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); + return nhg_connected_tree_is_empty(&nhe->nhg_dependents); } void zebra_nhg_dependents_del(struct nhg_hash_entry *from, struct nhg_hash_entry *dependent) { - nhg_connected_head_del(&from->nhg_dependents, dependent); + nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent); } void zebra_nhg_dependents_add(struct nhg_hash_entry *to, struct nhg_hash_entry *dependent) { - nhg_connected_head_add(&to->nhg_dependents, dependent); + nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent); } void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe) { - nhg_connected_head_init(&nhe->nhg_dependents); + nhg_connected_tree_init(&nhe->nhg_dependents); } /* Release this nhe from anything depending on it */ @@ -263,10 +242,9 @@ 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; - struct nhg_connected *tmp = NULL; - RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, - &nhe->nhg_dependents, tmp) { + frr_each_safe (nhg_connected_tree, &nhe->nhg_dependents, + rb_node_dep) { zebra_nhg_depends_del(rb_node_dep->nhe, nhe); } } @@ -319,8 +297,7 @@ static void *zebra_nhg_alloc(void *arg) /* 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) { + frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { zebra_nhg_dependents_add(rb_node_dep->nhe, nhe); } } @@ -401,17 +378,11 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -static int nhg_connected_cmp(const struct nhg_connected *con1, - const struct nhg_connected *con2) -{ - return (con1->nhe->id - con2->nhe->id); -} - static void zebra_nhg_process_grp(struct nexthop_group *nhg, - struct nhg_connected_head *depends, + struct nhg_connected_tree_head *depends, struct nh_grp *grp, uint8_t count) { - nhg_connected_head_init(depends); + nhg_connected_tree_init(depends); for (int i = 0; i < count; i++) { struct nhg_hash_entry *depend = NULL; @@ -422,7 +393,7 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, */ depend = zebra_nhg_lookup_id(grp[i].id); if (depend) { - nhg_connected_head_add(depends, 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 @@ -444,7 +415,7 @@ 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_head *nhg_depends, + struct nhg_connected_tree_head *nhg_depends, vrf_id_t vrf_id, afi_t afi, bool is_kernel_nh) { /* id counter to keep in sync with kernel */ @@ -490,7 +461,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, return created; } -static void handle_recursive_depend(struct nhg_connected_head *nhg_depends, +static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, struct nexthop *nh, afi_t afi) { struct nhg_hash_entry *depend = NULL; @@ -508,13 +479,13 @@ static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id, bool is_kernel_nh) { struct nexthop_group nhg = {}; - struct nhg_connected_head nhg_depends = {}; + struct nhg_connected_tree_head nhg_depends = {}; bool created = true; _nexthop_group_add_sorted(&nhg, nh); if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { - nhg_connected_head_init(&nhg_depends); + nhg_connected_tree_init(&nhg_depends); handle_recursive_depend(&nhg_depends, nh->resolved, afi); } @@ -567,7 +538,7 @@ static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx) static int nhg_ctx_process_new(struct nhg_ctx *ctx) { struct nexthop_group *nhg = NULL; - struct nhg_connected_head nhg_depends = {}; + struct nhg_connected_tree_head nhg_depends = {}; struct nhg_hash_entry *nhe = NULL; if (ctx->count) { @@ -576,13 +547,13 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) ctx->count); if (!zebra_nhg_find(&nhe, ctx->id, nhg, &nhg_depends, ctx->vrf_id, ctx->afi, true)) - nhg_connected_head_free(&nhg_depends); + nhg_connected_tree_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_head_free(&nhg_depends); + nhg_connected_tree_free(&nhg_depends); if (nhe) { if (ctx->id != nhe->id) @@ -721,14 +692,14 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) return nhe; } -static void depends_add(struct nhg_connected_head *head, +static void depends_add(struct nhg_connected_tree_head *head, struct nhg_hash_entry *depend) { - nhg_connected_head_add(head, depend); + nhg_connected_tree_add_nhe(head, depend); zebra_nhg_increment_ref(depend); } -static void depends_find_add(struct nhg_connected_head *head, +static void depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, afi_t afi) { struct nhg_hash_entry *depend = NULL; @@ -737,10 +708,10 @@ static void depends_find_add(struct nhg_connected_head *head, depends_add(head, depend); } -static void depends_decrement_free(struct nhg_connected_head *head) +static void depends_decrement_free(struct nhg_connected_tree_head *head) { - nhg_connected_head_decrement_ref(head); - nhg_connected_head_free(head); + nhg_connected_tree_decrement_ref(head); + nhg_connected_tree_free(head); } /* Rib-side, you get a nexthop group struct */ @@ -748,7 +719,7 @@ 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_connected_head nhg_depends = {}; + struct nhg_connected_tree_head nhg_depends = {}; /* Defualt the nhe to the afi and vrf of the route */ afi_t nhg_afi = rt_afi; @@ -761,7 +732,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) } if (nhg->nexthop->next) { - nhg_connected_head_init(&nhg_depends); + nhg_connected_tree_init(&nhg_depends); /* If its a group, create a dependency tree */ struct nexthop *nh = NULL; @@ -773,7 +744,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) nhg_afi = AFI_UNSPEC; nhg_vrf_id = 0; } else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { - nhg_connected_head_init(&nhg_depends); + nhg_connected_tree_init(&nhg_depends); handle_recursive_depend(&nhg_depends, nhg->nexthop->resolved, rt_afi); } @@ -791,9 +762,9 @@ void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { nexthop_group_free_delete(&nhe->nhg); /* Decrement to remove connection ref */ - nhg_connected_head_decrement_ref(&nhe->nhg_depends); - nhg_connected_head_free(&nhe->nhg_depends); - nhg_connected_head_free(&nhe->nhg_dependents); + nhg_connected_tree_decrement_ref(&nhe->nhg_depends); + nhg_connected_tree_free(&nhe->nhg_depends); + nhg_connected_tree_free(&nhe->nhg_dependents); } void zebra_nhg_free(void *arg) @@ -826,7 +797,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) nhe->refcnt--; if (!zebra_nhg_depends_is_empty(nhe)) - nhg_connected_head_decrement_ref(&nhe->nhg_depends); + nhg_connected_tree_decrement_ref(&nhe->nhg_depends); if (!nhe->is_kernel_nh && nhe->refcnt <= 0) zebra_nhg_uninstall_kernel(nhe); @@ -837,7 +808,7 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) nhe->refcnt++; if (!zebra_nhg_depends_is_empty(nhe)) - nhg_connected_head_increment_ref(&nhe->nhg_depends); + nhg_connected_tree_increment_ref(&nhe->nhg_depends); } void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) @@ -847,8 +818,8 @@ 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 */ - RB_FOREACH (rb_node_dep, nhg_connected_head, - &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)) return; @@ -862,8 +833,8 @@ 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) { + frr_each (nhg_connected_tree, &nhe->nhg_dependents, + rb_node_dep) { zebra_nhg_set_invalid(rb_node_dep->nhe); } } @@ -1480,7 +1451,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; - RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe->nhg_depends) { + frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { depend = rb_node_dep->nhe; /* diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index ff2c73433aa2..0be821267ef8 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -39,6 +39,7 @@ struct nh_grp { uint8_t weight; }; +PREDECL_RBTREE_UNIQ(nhg_connected_tree); struct nhg_hash_entry { uint32_t id; @@ -69,7 +70,7 @@ struct nhg_hash_entry { * Using a rb tree here to make lookups * faster with ID's. */ - RB_HEAD(nhg_connected_head, nhg_connected) nhg_depends, nhg_dependents; + struct nhg_connected_tree_head 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 @@ -96,11 +97,18 @@ struct nhg_hash_entry { /* Abstraction for connected trees */ struct nhg_connected { - RB_ENTRY(nhg_connected) nhg_entry; + struct nhg_connected_tree_item tree_item; struct nhg_hash_entry *nhe; }; -RB_PROTOTYPE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp); +static int nhg_connected_cmp(const struct nhg_connected *con1, + const struct nhg_connected *con2) +{ + return (con1->nhe->id - con2->nhe->id); +} + +DECLARE_RBTREE_UNIQ(nhg_connected_tree, struct nhg_connected, tree_item, + nhg_connected_cmp); enum nhg_ctx_op_e { @@ -150,17 +158,16 @@ 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_tree_init(struct nhg_connected_tree_head *head); +extern void nhg_connected_tree_free(struct nhg_connected_tree_head *head); +extern bool +nhg_connected_tree_is_empty(const struct nhg_connected_tree_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, - struct nhg_hash_entry *nhe); +nhg_connected_tree_root(struct nhg_connected_tree_head *head); +extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head, + struct nhg_hash_entry *nhe); +extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head, + struct nhg_hash_entry *nhe); /** * NHE abstracted tree functions. diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 45515e30c0e9..177c5a52562f 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1122,16 +1122,15 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) if (!zebra_nhg_depends_is_empty(nhe)) { vty_out(vty, "\tDepends:"); - RB_FOREACH (rb_node_dep, nhg_connected_head, - &nhe->nhg_depends) { + frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); } vty_out(vty, "\n"); } if (!zebra_nhg_dependents_is_empty(nhe)) { vty_out(vty, "\tDependents:"); - RB_FOREACH (rb_node_dep, nhg_connected_head, - &nhe->nhg_dependents) { + frr_each (nhg_connected_tree, &nhe->nhg_dependents, + rb_node_dep) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); } vty_out(vty, "\n"); @@ -1189,8 +1188,8 @@ 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); - RB_FOREACH (rb_node_dep, nhg_connected_head, - &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); } From ae9bfa067e9eae73d4366ddbd8b448823e26eb2d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 11:58:25 -0400 Subject: [PATCH 128/189] zebra: Install a route if the nhe is queued as well Before we install a route, we verify that the nhg_hash_entry is installed. Allow the nhe to be queued as well and still pass the route install along. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index f1a099bb5222..2346cb7f0db0 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1527,17 +1527,16 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, #ifdef HAVE_NETLINK if (re->nhe_id && zns->supports_nh) { - ctx->u.rinfo.nhe.id = zebra_nhg_get_resolved_id(re->nhe_id); + struct nhg_hash_entry *nhe = + zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id)); + ctx->u.rinfo.nhe.id = 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. + * Check if the nhe is installed/queued before doing anything + * with this route. */ - if (!CHECK_FLAG(zebra_nhg_lookup_id(ctx->u.rinfo.nhe.id)->flags, - NEXTHOP_GROUP_INSTALLED)) { + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { ret = ENOENT; goto done; } From 8dfbc657247d58e9888b7b04b8948558c1218e03 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:14:32 -0400 Subject: [PATCH 129/189] 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(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 13ea90254346..a28f183895f9 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 6be91da54aa9..67b4afb3a510 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 From f429bd1b24e92433c8cd3c6869953a45aee57b1e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 11:45:19 -0400 Subject: [PATCH 130/189] 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(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index a28f183895f9..5179533e750c 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 67b4afb3a510..6827be70724e 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 From 904ba1c8eea2c01210bf5e5f61680f56c6d3be3d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:18:27 -0400 Subject: [PATCH 131/189] zebra: A group isn't recursive if one depend is We were setting a group to be recursive if its first depend was. This is not the case; individual depends of the group might be recursive but the group itself is not. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 5179533e750c..a02df6b168c7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -720,6 +720,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) { struct nhg_hash_entry *nhe = NULL; struct nhg_connected_tree_head nhg_depends = {}; + bool recursive = false; /* Defualt the nhe to the afi and vrf of the route */ afi_t nhg_afi = rt_afi; @@ -747,12 +748,13 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) nhg_connected_tree_init(&nhg_depends); handle_recursive_depend(&nhg_depends, nhg->nexthop->resolved, rt_afi); + recursive = true; } if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, false)) depends_decrement_free(&nhg_depends); - else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + else if (recursive) SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); return nhe; From 32e757f4aeb089b764a11f11298c6aab7b1d815d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:25:21 -0400 Subject: [PATCH 132/189] zebra: Mark nhe valid if installed If the nhe was successfully installed, make sure its marked as valid. Not fully sure how/where the valid flag is going to be used yet. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index a02df6b168c7..24eae603f2cf 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1588,6 +1588,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); } else { flog_err( From 4b87c90d58a04650d8bc4316115c3233236431a0 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:26:29 -0400 Subject: [PATCH 133/189] 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(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6827be70724e..c89033b18c72 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. */ From 8dbc800f42797105b53fd385eb57ac30bc372d7d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 13:27:59 -0400 Subject: [PATCH 134/189] zebra: Prevent duplication and overflow in nhe2grp The kernel does not allow duplicate IDs in the same group, but we are perfectly find with it internally if two different nexthops resolve the the same nexthop (default route for instance). So, we have to handle this when we get ready to install. Further, pass the max group size in the arguments to ensure we don't overflow. Don't actually think this is possible due to multipath checking in nexthop_active_update() but better to be safe. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 4 ++-- zebra/zebra_nhg.c | 26 +++++++++++++++++++++----- zebra/zebra_nhg.h | 4 ++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 2346cb7f0db0..e4002252d3a1 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1589,8 +1589,8 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, /* 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); + ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp( + ctx->u.rinfo.nhe.nh_grp, nhe, MULTIPATH_NUM); zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 24eae603f2cf..870f4afb2786 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1444,13 +1444,16 @@ int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) } /* Convert a nhe into a group array */ -uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) +uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, + int max_num) { struct nhg_connected *rb_node_dep = NULL; struct nhg_hash_entry *depend = NULL; uint8_t i = 0; frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + bool duplicate = false; + depend = rb_node_dep->nhe; /* @@ -1467,11 +1470,24 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe) } } - grp[i].id = depend->id; - /* We aren't using weights for anything right now */ - grp[i].weight = 0; - i++; + /* Check for duplicate IDs, kernel doesn't like that */ + for (int j = 0; j < i; j++) { + if (depend->id == grp[j].id) + duplicate = true; + } + + if (!duplicate) { + grp[i].id = depend->id; + /* We aren't using weights for anything right now */ + grp[i].weight = 0; + i++; + } + + if (i >= max_num) + goto done; } + +done: return i; } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 0be821267ef8..e06d415b28ec 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -236,8 +236,8 @@ 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); +extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, + int size); void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); From 428b4c0a5d798d3a0c1984da7d02e0df86df978e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 25 Jul 2019 14:00:31 -0400 Subject: [PATCH 135/189] zebra: Give installed nhe's the zebra proto Give all nhg_hash_entrys we install into the kernel as nexthop objects a defined proto matching the zebra rib table one. This makes sense since nhe's are proto-independent and determined exclusively in zebra. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 1 + zebra/zebra_dplane.c | 1 + zebra/zebra_nhg.c | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 89fed59f7614..c6f15aef2a65 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -188,6 +188,7 @@ static inline int zebra2proto(int proto) proto = RTPROT_OPENFABRIC; break; case ZEBRA_ROUTE_TABLE: + case ZEBRA_NHG: proto = RTPROT_ZEBRA; break; default: diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e4002252d3a1..0e89ba3a27cd 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1577,6 +1577,7 @@ 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; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 870f4afb2786..3589c0e7b78f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1388,7 +1388,6 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { struct nhg_hash_entry *new_nhe = NULL; - // TODO: Add proto type here new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi); From 38e40db1c9695786d41a85661e313ce5a207866f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 1 Aug 2019 14:07:04 -0400 Subject: [PATCH 136/189] 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(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8c2caed1b0e1..44249d7dd112 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 c6f15aef2a65..3e913a7f5ff9 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 0e89ba3a27cd..e2c7bd7635ba 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 d0fde958e4c9..fede3bfcca4e 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 3589c0e7b78f..fb9e9135900c 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 e06d415b28ec..1fdda276cb82 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 c89033b18c72..bc647864ff7b 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 b85319df735a..d6ec6ac1658e 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 497846e0fae4..ac4c96147563 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); From 9a1588c4ce9ef163c9f4eeeed1a92e11133ed6c8 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 1 Aug 2019 14:24:35 -0400 Subject: [PATCH 137/189] zebra: Add handling for kernel del/update nexthop Add handling for delete/update nexthop object messages from the kernel. If someone deletes a nexthop object we are still using, send it back down. If the someone updates a nexthop we are using, replace that nexthop with ours. Routes are referencing this nexthop object ID and we resolved it ourselves, so we should force the other `someone` to submit to our will. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 40 ++---------- zebra/zebra_nhg.c | 148 +++++++++++++++++++++++++++++++++------------ zebra/zebra_nhg.h | 2 + 3 files changed, 116 insertions(+), 74 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3e913a7f5ff9..6e791b13369d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1942,6 +1942,10 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + + if (cmd == RTM_NEWNEXTHOP) + req.n.nlmsg_flags |= NLM_F_REPLACE; + req.n.nlmsg_type = cmd; req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; @@ -2287,11 +2291,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct nh_grp grp[MULTIPATH_NUM] = {}; /* Count of nexthops in group array */ uint8_t grp_count = 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) @@ -2367,41 +2368,12 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) vrf_id = nh.vrf_id; } - // TODO: Apparently we don't want changes - // to already created one in our table. - // They should be immutable... - // Gotta figure that one out. - - if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi, type, startup)) return -1; - - } 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, - "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table", - id); - return -1; - } - - zebra_nhg_set_invalid(nhe); - - // TODO: Probably won't need this if we expect - // upper level protocol to fix it. - 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, sending it back down", - nhe->id); - zebra_nhg_install_kernel(nhe); - } else - zebra_nhg_set_invalid(nhe); - } + } else if (h->nlmsg_type == RTM_DELNEXTHOP) + zebra_nhg_kernel_del(id); return 0; } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index fb9e9135900c..2027f98f6f53 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -458,7 +458,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, lookup.afi = afi; lookup.vrf_id = vrf_id; - lookup.type = type; + lookup.type = type ? type : ZEBRA_ROUTE_NHG; lookup.nhg = nhg; if (nhg_depends) @@ -576,12 +576,78 @@ static void zebra_nhg_set_dup(struct nhg_hash_entry *nhe) nhe->id); } +/* + * 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); + zebra_nhg_dependents_release(nhe); + if (nhe->ifp) + if_nhg_dependents_del(nhe->ifp, 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); +} + +static void zebra_nhg_release_id(struct nhg_hash_entry *nhe) +{ + hash_release(zrouter.nhgs_id, nhe); +} + + +static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe) +{ + zebra_nhg_release_id(nhe); + zebra_nhg_free(nhe); +} + +/* + * The kernel/other program has changed the state of a nexthop object we are + * using. + */ +static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe, + bool is_delete) +{ + if (nhe->refcnt) { + flog_err( + EC_ZEBRA_NHG_SYNC, + "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down", + (is_delete ? "deleted" : "updated"), nhe->id); + + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_install_kernel(nhe); + } else { + zebra_nhg_release_no_id(nhe); + zebra_nhg_handle_uninstall(nhe); + } +} + static int nhg_ctx_process_new(struct nhg_ctx *ctx) { struct nexthop_group *nhg = NULL; struct nhg_connected_tree_head nhg_depends = {}; + struct nhg_hash_entry *lookup = NULL; struct nhg_hash_entry *nhe = NULL; + lookup = zebra_nhg_lookup_id(ctx->id); + + if (lookup) { + /* This is already present in our table, hence an update + * that we did not initate. + */ + zebra_nhg_handle_kernel_state_change(lookup, false); + return 0; + } + if (ctx->count) { nhg = nexthop_group_new(); zebra_nhg_process_grp(nhg, &nhg_depends, ctx->u.grp, @@ -640,6 +706,25 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) return 0; } +static int nhg_ctx_process_del(struct nhg_ctx *ctx) +{ + struct nhg_hash_entry *nhe = NULL; + + nhe = zebra_nhg_lookup_id(ctx->id); + + 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", + ctx->id); + return 0; + } + + zebra_nhg_handle_kernel_state_change(nhe, true); + + return 0; +} + static void nhg_ctx_process_finish(struct nhg_ctx *ctx) { /* @@ -660,6 +745,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx) ret = nhg_ctx_process_new(ctx); break; case NHG_CTX_OP_DEL: + ret = nhg_ctx_process_del(ctx); case NHG_CTX_OP_NONE: break; } @@ -692,11 +778,6 @@ 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, int type, int startup) { - // 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; if (id > id_counter) @@ -736,6 +817,25 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, return 0; } +/* Kernel-side, received delete message */ +int zebra_nhg_kernel_del(uint32_t id) +{ + struct nhg_ctx *ctx = NULL; + + ctx = nhg_ctx_new(); + + ctx->id = id; + + nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL); + + if (queue_add(ctx)) { + nhg_ctx_process_finish(ctx); + return -1; + } + + return 0; +} + /* Some dependency helper functions */ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) { @@ -862,33 +962,6 @@ void zebra_nhg_free(void *arg) XFREE(MTYPE_NHG, 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); - zebra_nhg_dependents_release(nhe); - if (nhe->ifp) - if_nhg_dependents_del(nhe->ifp, 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); -} - -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) { nhe->refcnt--; @@ -1627,13 +1700,6 @@ 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 */ @@ -1642,6 +1708,8 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { int ret = dplane_nexthop_delete(nhe); + /* Change its type to us since we are installing it */ + nhe->type = ZEBRA_ROUTE_NHG; switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 1fdda276cb82..eb9173457c5d 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -230,6 +230,8 @@ 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, int type, int startup); +/* Del via kernel */ +extern int zebra_nhg_kernel_del(uint32_t id); /* Find via route creation */ extern struct nhg_hash_entry * From 815059466cdfb022ff5beec55f7ffee649db7600 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 1 Aug 2019 14:53:06 -0400 Subject: [PATCH 138/189] zebra: Move the supports_nh bool to a better place Move the supports_nh bool indicating whether the kernel we are using supports nexthop objects into the netlink kernel interface itself. Since only linux and netlink support nexthop object APIs for now this is fine. Signed-off-by: Stephen Worley --- zebra/if_netlink.c | 10 +--------- zebra/rt_netlink.c | 17 ++++++++++++++++- zebra/zebra_dplane.c | 17 +++++------------ zebra/zebra_nhg.c | 44 ++++++++++++++++++++++++++------------------ zebra/zebra_ns.h | 1 - 5 files changed, 48 insertions(+), 41 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 44249d7dd112..c09007bcb1d2 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1482,15 +1482,7 @@ void interface_list(struct zebra_ns *zns) * so we need to get the nexthop info * from the kernel before we can do that */ - - if (netlink_nexthop_read(zns)) { - /* If the nexthop read fails, assume the kernel - * cannot handle nexthop objects. - */ - zlog_debug("Nexthop objects disabled on this kernel"); - zns->supports_nh = false; - } else - zns->supports_nh = true; + netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 6e791b13369d..840354a8bc78 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -74,6 +74,8 @@ static vlanid_t filter_vlan = 0; +static bool supports_nh = false; + struct gw_family_t { uint16_t filler; uint16_t family; @@ -1644,7 +1646,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) RTA_PAYLOAD(rta)); } - if (dplane_ctx_get_nhe_id(ctx)) { + if (supports_nh) { /* Kernel supports nexthop objects */ addattr32(&req.n, sizeof(req), RTA_NH_ID, dplane_ctx_get_nhe_id(ctx)); @@ -1938,6 +1940,10 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) char buf[NL_PKT_BUF_SIZE]; } req; + /* Nothing to do if the kernel doesn't support nexthop objects */ + if (!supports_nh) + return 0; + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); @@ -2424,6 +2430,15 @@ int netlink_nexthop_read(struct zebra_ns *zns) return ret; ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd, &dp_info, 0, 1); + + if (!ret) + /* If we succesfully read in nexthop objects, + * this kernel must support them. + */ + supports_nh = true; + else if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Nexthop objects not supported on this kernel"); + return ret; } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e2c7bd7635ba..04aca1ac7e4d 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1526,7 +1526,7 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE)); #ifdef HAVE_NETLINK - if (re->nhe_id && zns->supports_nh) { + if (re->nhe_id) { struct nhg_hash_entry *nhe = zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id)); @@ -1594,11 +1594,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; - if (!zns->supports_nh) { - ret = EOPNOTSUPP; - goto done; - } - /* * TODO: Might not need to mark this as an update, since * it probably won't require two messages @@ -1896,12 +1891,8 @@ dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) if (ret == AOK) result = ZEBRA_DPLANE_REQUEST_QUEUED; else { - if (ret == EOPNOTSUPP) - result = ZEBRA_DPLANE_REQUEST_SUCCESS; - else - atomic_fetch_add_explicit( - &zdplane_info.dg_nexthop_errors, 1, - memory_order_relaxed); + atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1, + memory_order_relaxed); if (ctx) dplane_ctx_free(&ctx); } @@ -2078,6 +2069,8 @@ enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe) /* * Enqueue a nexthop update for the dataplane. + * + * Might not need this func since zebra's nexthop objects should be immutable? */ enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2027f98f6f53..9e54753bf01e 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -553,6 +553,29 @@ static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx) return ctx->op; } +static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, + struct nh_grp *grp, vrf_id_t vrf_id, + afi_t afi, int type, uint8_t count) +{ + struct nhg_ctx *ctx = NULL; + + ctx = nhg_ctx_new(); + + ctx->id = id; + ctx->vrf_id = vrf_id; + ctx->afi = afi; + ctx->type = type; + ctx->count = count; + + if (count) + /* Copy over the array */ + memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp)); + else if (nh) + ctx->u.nh = *nh; + + return ctx; +} + static bool zebra_nhg_contains_dup(struct nhg_hash_entry *nhe) { struct nhg_connected *rb_node_dep = NULL; @@ -717,7 +740,7 @@ static int nhg_ctx_process_del(struct nhg_ctx *ctx) EC_ZEBRA_BAD_NHG_MESSAGE, "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table", ctx->id); - return 0; + return -1; } zebra_nhg_handle_kernel_state_change(nhe, true); @@ -786,20 +809,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, */ id_counter = id; - ctx = nhg_ctx_new(); - - ctx->id = id; - ctx->vrf_id = vrf_id; - ctx->afi = afi; - ctx->type = type; - ctx->count = count; - - if (count) - /* Copy over the array */ - memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp)); - else - ctx->u.nh = *nh; - + ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count); nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW); /* Under statup conditions, we need to handle them immediately @@ -822,9 +832,7 @@ int zebra_nhg_kernel_del(uint32_t id) { struct nhg_ctx *ctx = NULL; - ctx = nhg_ctx_new(); - - ctx->id = id; + ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0); nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 11aa1b74c9f8..dc79a83db0d8 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -54,7 +54,6 @@ struct zebra_ns { struct nlsock netlink_cmd; /* command channel */ struct nlsock netlink_dplane; /* dataplane channel */ struct thread *t_netlink; - bool supports_nh; /* Does kernel support nexthop objects? */ #endif struct route_table *if_table; From bc541126e4058b6139f6b693a1adc9af2332317d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 1 Aug 2019 17:36:56 -0400 Subject: [PATCH 139/189] 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(-) diff --git a/zebra/connected.c b/zebra/connected.c index b69c5c6e713c..e21b778e3e02 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 13dd9c8dc13d..c2812aa47b91 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 42f8c812b44d..4e0163f8ac26 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 2652b12abf2d..35aa011c0d50 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 840354a8bc78..cdd7b5a92ad1 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 ecbf39dda02f..ab4c246d166f 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 bc647864ff7b..1440171584b5 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; From 6e72876478bf4dde05ef46b07b15beb818b313b2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 26 Aug 2019 17:06:10 -0400 Subject: [PATCH 140/189] zebra: TODO for hanlding blackhole attr exclusive Add a TODO statement for handling the exclusiveness of blackhole attributes. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cdd7b5a92ad1..98fe8b268725 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2004,7 +2004,8 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) &nh->gate.ipv6, IPV6_MAX_BYTELEN); break; case NEXTHOP_TYPE_BLACKHOLE: - // TODO: Handle this + // TODO: Handle this, Can't have OIF/Encap with + // it addattr_l(&req.n, sizeof(req), NHA_BLACKHOLE, NULL, 0); break; @@ -2237,6 +2238,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, 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) From 6384cbcb0eaed417b95e9bce9f666d4f8ef4d7ca Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 26 Aug 2019 17:09:31 -0400 Subject: [PATCH 141/189] zebra: Create depends after initial lookup Create any depends only after the initial hash lookup fails. Should reduce hashing cpu cycles significantly. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 128 +++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9e54753bf01e..b343778bf3a6 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -439,6 +439,17 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, } } +static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, + struct nexthop *nh, afi_t afi) +{ + struct nhg_hash_entry *depend = NULL; + struct nexthop_group resolved_ng = {}; + + _nexthop_group_add_sorted(&resolved_ng, nh); + + depend = zebra_nhg_rib_find(0, &resolved_ng, afi); + depends_add(nhg_depends, depend); +} static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, struct nexthop_group *nhg, @@ -450,19 +461,24 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, uint32_t old_id_counter = id_counter; bool created = false; + bool recursive = false; /* * 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.type = type ? type : ZEBRA_ROUTE_NHG; lookup.nhg = nhg; - if (nhg_depends) - lookup.nhg_depends = *nhg_depends; + if (lookup.nhg->nexthop->next) { + /* Groups can have all vrfs and AF's in them */ + lookup.afi = AFI_UNSPEC; + lookup.vrf_id = 0; + } else { + lookup.afi = afi; + lookup.vrf_id = vrf_id; + } if (id) (*nhe) = zebra_nhg_lookup_id(id); @@ -474,49 +490,58 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, id_counter = old_id_counter; if (!(*nhe)) { + /* Only hash/lookup the depends if the first lookup + * fails to find something. This should hopefully save a + * lot of cycles for larger ecmp sizes. + */ + if (nhg_depends) + /* If you don't want to hash on each nexthop in the + * nexthop group struct you can pass the depends + * directly. Kernel-side we do this since it just looks + * them up via IDs. + */ + lookup.nhg_depends = *nhg_depends; + else { + if (nhg->nexthop->next) { + nhg_connected_tree_init(&lookup.nhg_depends); + + /* If its a group, create a dependency tree */ + struct nexthop *nh = NULL; + + for (nh = nhg->nexthop; nh; nh = nh->next) + depends_find_add(&lookup.nhg_depends, + nh, afi); + } else if (CHECK_FLAG(nhg->nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) { + nhg_connected_tree_init(&lookup.nhg_depends); + handle_recursive_depend(&lookup.nhg_depends, + nhg->nexthop->resolved, + afi); + recursive = true; + } + } + (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc); created = true; - } + if (recursive) + SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE); + } return created; } -static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, - struct nexthop *nh, afi_t afi) -{ - struct nhg_hash_entry *depend = NULL; - struct nexthop_group resolved_ng = {}; - - _nexthop_group_add_sorted(&resolved_ng, nh); - - depend = zebra_nhg_rib_find(0, &resolved_ng, afi); - depends_add(nhg_depends, depend); -} - /* 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, int type) +static struct nhg_hash_entry * +zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type) { + struct nhg_hash_entry *nhe = NULL; struct nexthop_group nhg = {}; - struct nhg_connected_tree_head nhg_depends = {}; - bool created = true; _nexthop_group_add_sorted(&nhg, nh); - if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { - nhg_connected_tree_init(&nhg_depends); - handle_recursive_depend(&nhg_depends, nh->resolved, afi); - } + zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, 0); - if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, 0)) { - created = false; - depends_decrement_free(&nhg_depends); - } else { - if (zebra_nhg_depends_count(*nhe)) - SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE); - } - - return created; + return nhe; } static struct nhg_ctx *nhg_ctx_new() @@ -682,8 +707,8 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) /* These got copied over in zebra_nhg_alloc() */ nexthop_group_free_delete(&nhg); } else - zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi, - ctx->type); + nhe = zebra_nhg_find_nexthop(ctx->id, &ctx->u.nh, ctx->afi, + ctx->type); if (nhe) { if (ctx->id != nhe->id) { @@ -858,7 +883,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, 0); + nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0); nexthops_free(lookup); @@ -906,11 +931,7 @@ 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_connected_tree_head nhg_depends = {}; - bool recursive = false; - /* Defualt the nhe to the afi and vrf of the route */ - afi_t nhg_afi = rt_afi; vrf_id_t nhg_vrf_id = nhg->nexthop->vrf_id; if (!nhg) { @@ -919,30 +940,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) return NULL; } - if (nhg->nexthop->next) { - nhg_connected_tree_init(&nhg_depends); - - /* If its a group, create a dependency tree */ - struct nexthop *nh = NULL; - - for (nh = nhg->nexthop; nh; nh = nh->next) - depends_find_add(&nhg_depends, nh, rt_afi); - - /* change the afi/vrf_id since its a group */ - nhg_afi = AFI_UNSPEC; - nhg_vrf_id = 0; - } else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { - nhg_connected_tree_init(&nhg_depends); - handle_recursive_depend(&nhg_depends, nhg->nexthop->resolved, - rt_afi); - recursive = true; - } - - if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi, - 0)) - depends_decrement_free(&nhg_depends); - else if (recursive) - SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE); + zebra_nhg_find(&nhe, id, nhg, NULL, nhg_vrf_id, rt_afi, 0); return nhe; } From e4ac313b1280e15c13d12ff3dd25c7c09382920a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 6 Aug 2019 13:16:07 -0400 Subject: [PATCH 142/189] zebra: Check active count first in nhg_hash_equal Before checking the equivalence of the whole group itself, check to see if they contain the same number of non-recursive active nexthops. This should shorten lookup time for the case of non-resolved nexthop group creation. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index b343778bf3a6..3a2efacd9bea 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -387,13 +387,13 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->afi != nhe2->afi) return false; - 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; + if (!nexthop_group_equal(nhe1->nhg, nhe2->nhg)) + return false; + return true; } From 12ec584da837e2c3410190b202b7d30875d0a9dc Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 6 Aug 2019 13:40:19 -0400 Subject: [PATCH 143/189] lib: nexthop_group_equal() assume ordered Speed up nexthop_group_equal() by making it assume the groups it has been passed are ordered. This should always be the case. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index a79b2741c548..fb569360c486 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -132,10 +132,12 @@ struct nexthop *nexthop_exists(const struct nexthop_group *nhg, return NULL; } +/* This assumes ordered */ bool nexthop_group_equal(const struct nexthop_group *nhg1, const struct nexthop_group *nhg2) { - struct nexthop *nh = NULL; + struct nexthop *nh1 = NULL; + struct nexthop *nh2 = NULL; if (nhg1 && !nhg2) return false; @@ -147,8 +149,9 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, != nexthop_group_nexthop_num_no_recurse(nhg2)) return false; - for (nh = nhg1->nexthop; nh; nh = nh->next) { - if (!nexthop_exists(nhg2, nh)) + for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 && nh2; + nh1 = nh1->next, nh2 = nh2->next) { + if (!nexthop_same(nh1, nh2)) return false; } From a15e669ceb0c9adde7ca2370aae7168a0b6548bc Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 6 Aug 2019 17:30:16 -0400 Subject: [PATCH 144/189] lib: Call nexthop g_addr hashes together When hashing a nexthop, shove all the nexthop g_addr data together and pass it as one call to jhash2() to optimize a bit better. Signed-off-by: Stephen Worley --- lib/nexthop.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index e68e605a6f89..da7c934efa91 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -374,16 +374,28 @@ unsigned int nexthop_level(struct nexthop *nexthop) return rv; } +#define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */ + uint32_t nexthop_hash(const struct nexthop *nexthop) { + uint32_t key = 0x45afe398; + uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {}; key = jhash_3words(nexthop->type, nexthop->vrf_id, nexthop->nh_label_type, key); - /* gate and blackhole are together in a union */ - key = jhash(&nexthop->gate, sizeof(nexthop->gate), key); - key = jhash(&nexthop->src, sizeof(nexthop->src), key); - key = jhash(&nexthop->rmap_src, sizeof(nexthop->rmap_src), key); + + assert(((sizeof(nexthop->gate) + sizeof(nexthop->src) + + sizeof(nexthop->rmap_src)) + / 3) + == (GATE_SIZE * sizeof(uint32_t))); + + memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE); + memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE); + memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src, + GATE_SIZE); + + key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key); if (nexthop->nh_label) { int labels = nexthop->nh_label->num_labels; From 9ef49038d59e388a442c265d03d27c4d5e9c7e27 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 7 Aug 2019 11:33:01 -0400 Subject: [PATCH 145/189] 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(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index fb569360c486..8bb6fc9593c8 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 a765b4b76b13..291a259f9354 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 3a2efacd9bea..9e19c8d0e365 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 1440171584b5..52cc019d7c7c 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. */ From 2171b19c5a9be03429ceb90fb71b95cc9efe1349 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 7 Aug 2019 14:04:19 -0400 Subject: [PATCH 146/189] lib: Separate nexthop_group_equal() into recursive Separate nexthop_group_equal() into two versions. One that compares verses recurisvely resolved nexthops and one that doesn't. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 30 +++++++++++++++++++++++++++--- lib/nexthop_group.h | 5 +++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 8bb6fc9593c8..86c885012c83 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -133,8 +133,8 @@ struct nexthop *nexthop_exists(const struct nexthop_group *nhg, } /* This assumes ordered */ -bool nexthop_group_equal(const struct nexthop_group *nhg1, - const struct nexthop_group *nhg2) +bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2) { struct nexthop *nh1 = NULL; struct nexthop *nh2 = NULL; @@ -149,7 +149,7 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, != nexthop_group_nexthop_num_no_recurse(nhg2)) return false; - for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 && nh2; + for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2; nh1 = nh1->next, nh2 = nh2->next) { if (!nexthop_same(nh1, nh2)) return false; @@ -158,6 +158,30 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, return true; } +/* This assumes ordered */ +bool nexthop_group_equal(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2) +{ + struct nexthop *nh1 = NULL; + struct nexthop *nh2 = NULL; + + if (nhg1 && !nhg2) + return false; + + if (!nhg1 && !nhg2) + return false; + + if (nexthop_group_nexthop_num(nhg1) != nexthop_group_nexthop_num(nhg2)) + return false; + + for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2; + nh1 = nexthop_next(nh1), nh2 = nexthop_next(nh2)) { + if (!nexthop_same(nh1, nh2)) + return false; + } + + return true; +} struct nexthop_group *nexthop_group_new(void) { return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group)); diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 291a259f9354..378b0ce6bb71 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -115,6 +115,11 @@ void nexthop_group_interface_state_change(struct interface *ifp, extern struct nexthop *nexthop_exists(const struct nexthop_group *nhg, const struct nexthop *nh); +/* This assumes ordered */ +extern bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2); + +/* This assumes ordered */ extern bool nexthop_group_equal(const struct nexthop_group *nhg1, const struct nexthop_group *nhg2); From 2001be6cc0926bfb5c38d64b74399beff13e00b2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 7 Aug 2019 14:06:22 -0400 Subject: [PATCH 147/189] zebra: NHE use nexthop_group_equal_no_recurse() Update nhg_hash_entry to use the non-recursive version of nexthop_group_equal() since it doesn't really need to compare all of those. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9e19c8d0e365..8e7592c2b0b1 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -395,7 +395,7 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg)) return false; - if (!nexthop_group_equal(nhe1->nhg, nhe2->nhg)) + if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg)) return false; return true; From 986a6617cc9425dfa4f9fcc879a4d98a3ab00b7c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 7 Aug 2019 13:47:34 -0400 Subject: [PATCH 148/189] 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(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index da7c934efa91..3ab728449216 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 5558e857f664..dfb30a1bceba 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 52cc019d7c7c..d4abb61f22b3 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 */ From df9069cd18a3af3d6c6a2452d2daf5a830010bc5 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 8 Aug 2019 15:53:58 -0400 Subject: [PATCH 149/189] zebra: Add some more output to show nexthop-group Add some more detailed output to `show nexthop-group`. It closely resembles the output of `show ip routes`. Signed-off-by: Stephen Worley --- zebra/zebra_vty.c | 130 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 11 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 177c5a52562f..2ec24466f3fe 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1105,30 +1105,142 @@ DEFUN (ip_nht_default_route, static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) { - struct nexthop *nhop = NULL; + struct nexthop *nexthop = NULL; struct nhg_connected *rb_node_dep = NULL; + char buf[SRCDEST2STR_BUFFER]; + + struct vrf *nhe_vrf = vrf_lookup_by_id(nhe->vrf_id); vty_out(vty, "ID: %u\n", nhe->id); - vty_out(vty, "\tRefCnt: %d\n", nhe->refcnt); + vty_out(vty, " RefCnt: %d\n", nhe->refcnt); + + if (nhe_vrf) + vty_out(vty, " VRF: %s\n", nhe_vrf->name); + else + vty_out(vty, " VRF: UNKNOWN\n"); + + 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, "\tValid"); + vty_out(vty, " Valid"); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) vty_out(vty, ", Installed"); vty_out(vty, "\n"); } if (nhe->ifp) - vty_out(vty, "\tInterface Index: %d\n", nhe->ifp->ifindex); + vty_out(vty, " Interface Index: %d\n", nhe->ifp->ifindex); if (!zebra_nhg_depends_is_empty(nhe)) { - - vty_out(vty, "\tDepends:"); + vty_out(vty, " Depends:"); frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); } vty_out(vty, "\n"); } + + for (ALL_NEXTHOPS_PTR(nhe->nhg, nexthop)) { + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out(vty, " "); + else + /* Make recursive nexthops a bit more clear */ + vty_out(vty, " "); + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, " %s", inet_ntoa(nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " %s", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, + sizeof buf)); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + + case NEXTHOP_TYPE_IFINDEX: + vty_out(vty, " directly connected %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out(vty, " unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + vty_out(vty, " (ICMP unreachable)"); + break; + case BLACKHOLE_ADMINPROHIB: + vty_out(vty, " (ICMP admin-prohibited)"); + break; + case BLACKHOLE_NULL: + vty_out(vty, " (blackhole)"); + break; + case BLACKHOLE_UNSPEC: + break; + } + break; + default: + break; + } + + struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); + + if (vrf) + vty_out(vty, " (vrf %s)", vrf->name); + else + vty_out(vty, " (vrf UNKNOWN)"); + + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out(vty, " inactive"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out(vty, " onlink"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out(vty, " (recursive)"); + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->src.ipv4.s_addr) { + if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, + sizeof buf)) + vty_out(vty, ", src %s", buf); + } + break; + case NEXTHOP_TYPE_IPV6: + 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)) + vty_out(vty, ", src %s", buf); + } + break; + default: + break; + } + + /* Label information */ + if (nexthop->nh_label && nexthop->nh_label->num_labels) { + vty_out(vty, ", label %s", + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, buf, + sizeof buf, 1)); + } + + vty_out(vty, "\n"); + } + if (!zebra_nhg_dependents_is_empty(nhe)) { - vty_out(vty, "\tDependents:"); + vty_out(vty, " Dependents:"); frr_each (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { vty_out(vty, " (%u)", rb_node_dep->nhe->id); @@ -1136,10 +1248,6 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) vty_out(vty, "\n"); } - for (ALL_NEXTHOPS_PTR(nhe->nhg, nhop)) { - vty_out(vty, "\t"); - nexthop_group_write_nexthop(vty, nhop); - } } static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id) From 0ad40d16159ff61febd1d884d035dfd8fa47873b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 8 Aug 2019 16:03:39 -0400 Subject: [PATCH 150/189] zebra: Add nhe_id to show ip route detailed When querying for detailed route information, show the nexthop group id for its nh_hash_entry in the output before listing the nexthops. Signed-off-by: Stephen Worley --- zebra/zebra_vty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 2ec24466f3fe..6396e1c82098 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -260,6 +260,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, tm->tm_hour); vty_out(vty, " ago\n"); + vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { char addrstr[32]; From cba6a409cfea9bf79ffb1088a1a15736cdd4db1a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 11:07:53 -0400 Subject: [PATCH 151/189] lib: Nexthop hash onlink and ifindex with one call In the nexthop hashing function, lets reduce the hash calls as much as possible. So, reduce the onlink and infindex to one call to jhash_2words(). Signed-off-by: Stephen Worley --- lib/nexthop.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 3ab728449216..3f6d9ad71138 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -435,19 +435,9 @@ uint32_t nexthop_hash(const struct nexthop *nexthop) key = jhash_1word(nexthop->nh_label->label[i], key); } - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4_IFINDEX: - case NEXTHOP_TYPE_IPV6_IFINDEX: - case NEXTHOP_TYPE_IFINDEX: - key = jhash_1word(nexthop->ifindex, key); - break; - case NEXTHOP_TYPE_BLACKHOLE: - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV6: - break; - } - - key = jhash_1word(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), key); + key = jhash_2words(nexthop->ifindex, + CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), + key); return key; } From 62991a11679da8912815c763980a505d1ad37ed7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 11:09:46 -0400 Subject: [PATCH 152/189] zebra: NHE hash reduce calls to jhash Reduce the two calls to jhash to one jhash_3words() call to save some more hashing time. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 8e7592c2b0b1..19119e62c92a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -362,9 +362,8 @@ uint32_t zebra_nhg_hash_key(const void *arg) uint32_t key = 0x5a351234; - key = jhash_2words(nhe->vrf_id, nhe->afi, key); - - key = jhash_1word(nexthop_group_hash(nhe->nhg), key); + key = jhash_3words(nhe->vrf_id, nhe->afi, nexthop_group_hash(nhe->nhg), + key); return key; } From 73a381871edd64e841ee6040423cfaca25117b1f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 11:27:09 -0400 Subject: [PATCH 153/189] lib: Add nexthop quick hash api Add a nexthop hashing api for only hashing on word-sized attributes. Calling the jhash/jhash2 function is quite slow in scaled envrionments but sometimes you do need a more granular hash. The tradeoff here is that hashtable buckets using this hash might be more full. Signed-off-by: Stephen Worley --- lib/nexthop.c | 44 +++++++++++++++++++++++++++----------------- lib/nexthop.h | 8 ++++++++ 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 3f6d9ad71138..017131882725 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -387,29 +387,14 @@ unsigned int nexthop_level(struct nexthop *nexthop) return rv; } -#define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */ - -uint32_t nexthop_hash(const struct nexthop *nexthop) +/* Only hash word-sized things, let cmp do the rest. */ +uint32_t nexthop_hash_quick(const struct nexthop *nexthop) { - uint32_t key = 0x45afe398; - uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {}; key = jhash_3words(nexthop->type, nexthop->vrf_id, nexthop->nh_label_type, key); - assert(((sizeof(nexthop->gate) + sizeof(nexthop->src) - + sizeof(nexthop->rmap_src)) - / 3) - == (GATE_SIZE * sizeof(uint32_t))); - - memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE); - memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE); - memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src, - GATE_SIZE); - - key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key); - if (nexthop->nh_label) { int labels = nexthop->nh_label->num_labels; int i = 0; @@ -442,6 +427,31 @@ uint32_t nexthop_hash(const struct nexthop *nexthop) return key; } + +#define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */ + +/* For a more granular hash */ +uint32_t nexthop_hash(const struct nexthop *nexthop) +{ + uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {}; + /* Get all the quick stuff */ + uint32_t key = nexthop_hash_quick(nexthop); + + assert(((sizeof(nexthop->gate) + sizeof(nexthop->src) + + sizeof(nexthop->rmap_src)) + / 3) + == (GATE_SIZE * sizeof(uint32_t))); + + memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE); + memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE); + memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src, + GATE_SIZE); + + key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key); + + return key; +} + void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, struct nexthop *rparent) { diff --git a/lib/nexthop.h b/lib/nexthop.h index dfb30a1bceba..480c4cc3dd69 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -137,6 +137,14 @@ void nexthop_del_labels(struct nexthop *); * 32-bit hash of nexthop */ uint32_t nexthop_hash(const struct nexthop *nexthop); +/* + * Hash a nexthop only on word-sized attributes: + * - vrf_id + * - ifindex + * - type + * - (some) flags + */ +uint32_t nexthop_hash_quick(const struct nexthop *nexthop); extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2); extern bool nexthop_same_no_labels(const struct nexthop *nh1, From b7537db6395062ebb8d6ef979eff7a91a6181eec Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 12:35:58 -0400 Subject: [PATCH 154/189] zebra: Add common netlink mpls stack building path There was some code copypasta for mpls stack building in the netlink install path. Reduced that to a common function. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 92 ++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 98fe8b268725..3ffb80b4825e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1074,6 +1074,35 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family, } } +static int build_label_stack(struct mpls_label_stack *nh_label, + mpls_lse_t *out_lse, char *label_buf, + size_t label_buf_size) +{ + char label_buf1[20]; + int num_labels = 0; + + for (int i = 0; nh_label && i < nh_label->num_labels; i++) { + if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) + continue; + + if (IS_ZEBRA_DEBUG_KERNEL) { + if (!num_labels) + sprintf(label_buf, "label %u", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%u", nh_label->label[i]); + strlcat(label_buf, label_buf1, label_buf_size); + } + } + + out_lse[num_labels] = + mpls_lse_encode(nh_label->label[i], 0, 0, 0); + num_labels++; + } + + return num_labels; +} + /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. @@ -1091,10 +1120,12 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, struct rtmsg *rtmsg, size_t req_size, int cmd) { - struct mpls_label_stack *nh_label; + mpls_lse_t out_lse[MPLS_MAX_LABELS]; - int num_labels = 0; char label_buf[256]; + int num_labels = 0; + + assert(nexthop); /* * label_buf is *only* currently used within debugging. @@ -1104,30 +1135,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, */ label_buf[0] = '\0'; - assert(nexthop); - char label_buf1[20]; - - nh_label = nexthop->nh_label; - - for (int i = 0; nh_label && i < nh_label->num_labels; i++) { - if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) - continue; - - if (IS_ZEBRA_DEBUG_KERNEL) { - if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); - else { - sprintf(label_buf1, "/%u", nh_label->label[i]); - strlcat(label_buf, label_buf1, - sizeof(label_buf)); - } - } - - out_lse[num_labels] = - mpls_lse_encode(nh_label->label[i], 0, 0, 0); - num_labels++; - } + num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf, + sizeof(label_buf)); if (num_labels) { /* Set the BoS bit */ @@ -1272,16 +1281,17 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, struct rtmsg *rtmsg, const union g_addr **src) { - struct mpls_label_stack *nh_label; mpls_lse_t out_lse[MPLS_MAX_LABELS]; - int num_labels = 0; char label_buf[256]; + int num_labels = 0; rtnh->rtnh_len = sizeof(*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rta->rta_len += rtnh->rtnh_len; + assert(nexthop); + /* * label_buf is *only* currently used within debugging. * As such when we assign it we are guarding it inside @@ -1290,30 +1300,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, */ label_buf[0] = '\0'; - assert(nexthop); - char label_buf1[20]; - - nh_label = nexthop->nh_label; - - for (int i = 0; nh_label && i < nh_label->num_labels; i++) { - if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) - continue; - - if (IS_ZEBRA_DEBUG_KERNEL) { - if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); - else { - sprintf(label_buf1, "/%u", nh_label->label[i]); - strlcat(label_buf, label_buf1, - sizeof(label_buf)); - } - } - - out_lse[num_labels] = - mpls_lse_encode(nh_label->label[i], 0, 0, 0); - num_labels++; - } + num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf, + sizeof(label_buf)); if (num_labels) { /* Set the BoS bit */ From 8d03bc501b5f9cbcb1814d79d750778f56a492da Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 15:46:22 -0400 Subject: [PATCH 155/189] zebra: Handle nhg_hash_entry encaps/more debugging Add code for handling nexthop group hash entry encaps and sending them to the kernel. Add some more debugging information for the encaps and groups in general. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 108 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 20 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3ffb80b4825e..18d1eee9e366 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -50,6 +50,7 @@ #include "vty.h" #include "mpls.h" #include "vxlan.h" +#include "printfrr.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_ns.h" @@ -1895,19 +1896,20 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) return suc; } -/** - * _netlink_nexthop_build_group() - Build a nexthop_grp struct for a nlmsg - * - * @n: Netlink message header struct - * @req_size: Size allocated for this message - * @z_grp: Array of nh_grp structs - * @count: How many depencies there are - */ +/* Char length to debug ID with */ +#define ID_LENGTH 10 + static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, + uint32_t id, const struct nh_grp *z_grp, const uint8_t count) { struct nexthop_grp grp[count]; + /* Need space for max group size, "/", and null term */ + char buf[(MULTIPATH_NUM * (ID_LENGTH + 1)) + 1]; + char buf1[ID_LENGTH + 2]; + + buf[0] = '\0'; memset(grp, 0, sizeof(grp)); @@ -1915,9 +1917,23 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, for (int i = 0; i < count; i++) { grp[i].id = z_grp[i].id; grp[i].weight = z_grp[i].weight; + + if (IS_ZEBRA_DEBUG_KERNEL) { + if (i == 0) + snprintf(buf, sizeof(buf1), "group %u", + grp[i].id); + else { + snprintf(buf1, sizeof(buf1), "/%u", + grp[i].id); + strlcat(buf, buf1, sizeof(buf)); + } + } } addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp)); } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: ID (%u): %s", __func__, id, buf); } /** @@ -1935,11 +1951,18 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) char buf[NL_PKT_BUF_SIZE]; } req; + mpls_lse_t out_lse[MPLS_MAX_LABELS]; + char label_buf[256]; + int num_labels = 0; + size_t req_size = sizeof(req); + /* Nothing to do if the kernel doesn't support nexthop objects */ if (!supports_nh) return 0; - memset(&req, 0, sizeof(req)); + label_buf[0] = '\0'; + + memset(&req, 0, req_size); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; @@ -1962,12 +1985,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) return -1; } - addattr32(&req.n, sizeof(req), NHA_ID, id); + addattr32(&req.n, req_size, NHA_ID, id); if (cmd == RTM_NEWNEXTHOP) { if (dplane_ctx_get_nhe_nh_grp_count(ctx)) _netlink_nexthop_build_group( - &req.n, sizeof(req), + &req.n, req_size, id, dplane_ctx_get_nhe_nh_grp(ctx), dplane_ctx_get_nhe_nh_grp_count(ctx)); else { @@ -1983,20 +2006,20 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) switch (nh->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - addattr_l(&req.n, sizeof(req), NHA_GATEWAY, + addattr_l(&req.n, req_size, NHA_GATEWAY, &nh->gate.ipv4, IPV4_MAX_BYTELEN); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - addattr_l(&req.n, sizeof(req), NHA_GATEWAY, + addattr_l(&req.n, req_size, NHA_GATEWAY, &nh->gate.ipv6, IPV6_MAX_BYTELEN); break; case NEXTHOP_TYPE_BLACKHOLE: - // TODO: Handle this, Can't have OIF/Encap with - // it - addattr_l(&req.n, sizeof(req), NHA_BLACKHOLE, - NULL, 0); - break; + addattr_l(&req.n, req_size, NHA_BLACKHOLE, NULL, + 0); + /* Blackhole shouldn't have anymore attributes + */ + goto nexthop_done; case NEXTHOP_TYPE_IFINDEX: /* Don't need anymore info for this */ break; @@ -2009,8 +2032,53 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) return -1; } - addattr32(&req.n, sizeof(req), NHA_OIF, nh->ifindex); - // TODO: Handle Encap + addattr32(&req.n, req_size, NHA_OIF, nh->ifindex); + + num_labels = + build_label_stack(nh->nh_label, out_lse, + label_buf, sizeof(label_buf)); + + if (num_labels) { + /* Set the BoS bit */ + out_lse[num_labels - 1] |= + htonl(1 << MPLS_LS_S_SHIFT); + + /* + * TODO: MPLS unsupported for now in kernel. + */ + if (req.nhm.nh_family == AF_MPLS) + goto nexthop_done; +#if 0 + addattr_l(&req.n, req_size, NHA_NEWDST, + &out_lse, + num_labels + * sizeof(mpls_lse_t)); +#endif + else { + struct rtattr *nest; + uint16_t encap = LWTUNNEL_ENCAP_MPLS; + + addattr_l(&req.n, req_size, + NHA_ENCAP_TYPE, &encap, + sizeof(uint16_t)); + nest = addattr_nest(&req.n, req_size, + NHA_ENCAP); + addattr_l(&req.n, req_size, + MPLS_IPTUNNEL_DST, &out_lse, + num_labels + * sizeof(mpls_lse_t)); + addattr_nest_end(&req.n, nest); + } + } + + nexthop_done: + if (IS_ZEBRA_DEBUG_KERNEL) { + char buf[NEXTHOP_STRLEN]; + + snprintfrr(buf, sizeof(buf), "%pNHv", nh); + zlog_debug("%s: ID (%u): %s (%u) %s ", __func__, + id, buf, nh->vrf_id, label_buf); + } } req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx)); From 10200d4054e1b2ea9579c5e7b01feee09bf79338 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 17:58:59 -0400 Subject: [PATCH 156/189] zebra: Add some getters for nhg_ctx Add some getters for the nhg_ctx struct. Probably unnecessary at this point since they are all static but if they ever become public it will be nice to have them. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 68 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 19119e62c92a..a9c0f8002de2 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -561,6 +561,11 @@ static void nhg_ctx_free(struct nhg_ctx *ctx) XFREE(MTYPE_NHG_CTX, ctx); } +static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx) +{ + return ctx->id; +} + static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_result status) { ctx->status = status; @@ -581,6 +586,36 @@ static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx) return ctx->op; } +static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx) +{ + return ctx->vrf_id; +} + +static int nhg_ctx_get_type(const struct nhg_ctx *ctx) +{ + return ctx->type; +} + +static int nhg_ctx_get_afi(const struct nhg_ctx *ctx) +{ + return ctx->afi; +} + +static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx) +{ + return &ctx->u.nh; +} + +static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx) +{ + return ctx->count; +} + +static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx) +{ + return ctx->u.grp; +} + static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_grp *grp, vrf_id_t vrf_id, afi_t afi, int type, uint8_t count) @@ -689,7 +724,13 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) struct nhg_hash_entry *lookup = NULL; struct nhg_hash_entry *nhe = NULL; - lookup = zebra_nhg_lookup_id(ctx->id); + uint32_t id = nhg_ctx_get_id(ctx); + uint8_t count = nhg_ctx_get_count(ctx); + vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx); + int type = nhg_ctx_get_type(ctx); + afi_t afi = nhg_ctx_get_afi(ctx); + + lookup = zebra_nhg_lookup_id(id); if (lookup) { /* This is already present in our table, hence an update @@ -699,22 +740,22 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) return 0; } - if (ctx->count) { + if (nhg_ctx_get_count(ctx)) { nhg = nexthop_group_new(); - 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->type, ctx->afi)) + zebra_nhg_process_grp(nhg, &nhg_depends, nhg_ctx_get_grp(ctx), + count); + if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type, + afi)) depends_decrement_free(&nhg_depends); /* 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->type); + nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi, + type); if (nhe) { - if (ctx->id != nhe->id) { + if (id != nhe->id) { struct nhg_hash_entry *kernel_nhe = NULL; /* Duplicate but with different ID from @@ -731,7 +772,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) * track them. */ - kernel_nhe = zebra_nhg_copy(nhe, ctx->id); + kernel_nhe = zebra_nhg_copy(nhe, id); zebra_nhg_insert_id(kernel_nhe); zebra_nhg_set_dup(kernel_nhe); } else if (zebra_nhg_contains_dup(nhe)) { @@ -750,7 +791,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, "Zebra failed to find or create a nexthop hash entry for ID (%u)", - ctx->id); + id); return -1; } @@ -760,14 +801,15 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) static int nhg_ctx_process_del(struct nhg_ctx *ctx) { struct nhg_hash_entry *nhe = NULL; + uint32_t id = nhg_ctx_get_id(ctx); - nhe = zebra_nhg_lookup_id(ctx->id); + nhe = zebra_nhg_lookup_id(id); 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", - ctx->id); + id); return -1; } From 3e347f4181db349299b2dd05bea11b030770af71 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 18:13:30 -0400 Subject: [PATCH 157/189] zebra: Free labels on nhg_ctx from kernel If we get a nexthop group from the kernel with labels and queue it as a context to process later, we have to free the label stack we allocated. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index a9c0f8002de2..c22bf349b75c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -820,11 +820,21 @@ static int nhg_ctx_process_del(struct nhg_ctx *ctx) static void nhg_ctx_process_finish(struct nhg_ctx *ctx) { + struct nexthop *nh; + /* * Just freeing for now, maybe do something more in the future * based on flag. */ + if (nhg_ctx_get_count(ctx)) + goto done; + + nh = nhg_ctx_get_nh(ctx); + + nexthop_del_labels(nh); + +done: if (ctx) nhg_ctx_free(ctx); } From 1b366e63beb7fc9b758c6a61d918c4bf14005bd8 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 12 Aug 2019 20:09:59 -0400 Subject: [PATCH 158/189] zebra: Handle out of order kernel nexthop groups Add a mechanism to requeue groups we receive from the kernel if the IDs are in a weird order (Group ID is lower than individual nexthop IDs for example). Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 76 +++++++++++++++++++++++++++++++---------------- zebra/zebra_nhg.h | 5 ++-- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c22bf349b75c..4130365f2d0a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -408,9 +408,9 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -static void zebra_nhg_process_grp(struct nexthop_group *nhg, - struct nhg_connected_tree_head *depends, - struct nh_grp *grp, uint8_t count) +static int zebra_nhg_process_grp(struct nexthop_group *nhg, + struct nhg_connected_tree_head *depends, + struct nh_grp *grp, uint8_t count) { nhg_connected_tree_init(depends); @@ -428,7 +428,7 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, 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; + return -1; } /* @@ -440,6 +440,8 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg, copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, NULL); } + + return 0; } static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, @@ -566,12 +568,12 @@ static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx) return ctx->id; } -static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_result status) +static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status) { ctx->status = status; } -static enum nhg_ctx_result nhg_ctx_get_status(const struct nhg_ctx *ctx) +static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx) { return ctx->status; } @@ -742,8 +744,13 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) if (nhg_ctx_get_count(ctx)) { nhg = nexthop_group_new(); - zebra_nhg_process_grp(nhg, &nhg_depends, nhg_ctx_get_grp(ctx), - count); + if (zebra_nhg_process_grp(nhg, &nhg_depends, + nhg_ctx_get_grp(ctx), count)) { + depends_decrement_free(&nhg_depends); + nexthop_group_free_delete(&nhg); + return ENOENT; + } + if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type, afi)) depends_decrement_free(&nhg_depends); @@ -839,6 +846,22 @@ static void nhg_ctx_process_finish(struct nhg_ctx *ctx) nhg_ctx_free(ctx); } +static int queue_add(struct nhg_ctx *ctx) +{ + /* If its queued or already processed do nothing */ + if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED) + 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; +} + int nhg_ctx_process(struct nhg_ctx *ctx) { int ret = 0; @@ -846,6 +869,19 @@ 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 + && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) { + /* Depends probably came before group, re-queue. + * + * Only going to retry once, hence just using status + * flag rather than counter. + */ + nhg_ctx_set_status(ctx, NHG_CTX_NONE); + if (queue_add(ctx) == 0) { + nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED); + return 0; + } + } break; case NHG_CTX_OP_DEL: ret = nhg_ctx_process_del(ctx); @@ -860,22 +896,6 @@ int nhg_ctx_process(struct nhg_ctx *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, int type, @@ -959,7 +979,9 @@ depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, struct nhg_hash_entry *depend = NULL; depend = depends_find(nh, afi); - depends_add(head, depend); + + if (depend) + depends_add(head, depend); return depend; } @@ -970,7 +992,9 @@ 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); + + if (depend) + depends_add(head, depend); return depend; } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index eb9173457c5d..812d9a1a90e8 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -125,9 +125,10 @@ enum nhg_ctx_op_e { NHG_CTX_OP_DEL, }; -enum nhg_ctx_result { +enum nhg_ctx_status { NHG_CTX_NONE = 0, NHG_CTX_QUEUED, + NHG_CTX_REQUEUED, NHG_CTX_SUCCESS, NHG_CTX_FAILURE, }; @@ -159,7 +160,7 @@ struct nhg_ctx { } u; enum nhg_ctx_op_e op; - enum nhg_ctx_result status; + enum nhg_ctx_status status; }; From 4d21c7c0868e16d37a795dd4da999a1707812c56 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 20 Aug 2019 15:08:01 -0400 Subject: [PATCH 159/189] zebra: Only use passed afi for blackhole/ifindex nexthops Only used the afi passed into `zebra_nhg_find()` for nexthops that are blackhole/ifindex. Others should use the type actually declared in the nexthop struct itself. Basically, nexthop objects of type blackhole/ifindex in the kernel must have an address family, they cannot be ambigious and be shared. This is some requirement in the linux ip core code. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4130365f2d0a..8cc18771065b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -481,7 +481,29 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, lookup.afi = AFI_UNSPEC; lookup.vrf_id = 0; } else { - lookup.afi = afi; + switch (lookup.nhg->nexthop->type) { + case (NEXTHOP_TYPE_IFINDEX): + case (NEXTHOP_TYPE_BLACKHOLE): + /* + * This switch case handles setting the afi different + * for ipv4/v6 routes. Ifindex/blackhole nexthop + * objects cannot be ambiguous, they must be Address + * Family specific. If we get here, we will either use + * the AF of the route, or the one we got passed from + * here from the kernel. + */ + lookup.afi = afi; + break; + case (NEXTHOP_TYPE_IPV4_IFINDEX): + case (NEXTHOP_TYPE_IPV4): + lookup.afi = AFI_IP; + break; + case (NEXTHOP_TYPE_IPV6_IFINDEX): + case (NEXTHOP_TYPE_IPV6): + lookup.afi = AFI_IP6; + break; + } + lookup.vrf_id = vrf_id; } From 61d9ffe168b4890bb1a91dc2907e00d3c5cd38f2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 26 Aug 2019 18:20:45 -0400 Subject: [PATCH 160/189] zebra: Only show route nexthop group ID when asked In lieu of the fact that we probably shouldn't change show command output too much, changing this to only give nhe_id output when the user explicitly asks for it. Probably only going to be used for debugging for now anyway. Signed-off-by: Stephen Worley --- zebra/zebra_vty.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6396e1c82098..2ff05e4858ae 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -64,7 +64,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, bool supernets_only, int type, unsigned short ospf_instance_id); static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, - int mcast, bool use_fib); + int mcast, bool use_fib, bool show_ng); static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table); static void vty_show_ip_route_summary_prefix(struct vty *vty, @@ -156,7 +156,7 @@ DEFUN (show_ip_rpf_addr, re = rib_match_ipv4_multicast(VRF_DEFAULT, addr, &rn); if (re) - vty_show_ip_route_detail(vty, rn, 1, false); + vty_show_ip_route_detail(vty, rn, 1, false, false); else vty_out(vty, "%% No match for RPF lookup\n"); @@ -188,7 +188,7 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop) /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, - int mcast, bool use_fib) + int mcast, bool use_fib, bool show_ng) { struct route_entry *re; struct nexthop *nexthop; @@ -260,7 +260,9 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, tm->tm_hour); vty_out(vty, " ago\n"); - vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); + if (show_ng) + vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); + for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { char addrstr[32]; @@ -1557,7 +1559,7 @@ DEFPY (show_route_detail, |X:X::X:X/M$prefix\ >\ >\ - [json$json]", + [json$json] [nexthop-group$ng]", SHOW_STR IP_STR "IPv6 forwarding table\n" @@ -1571,7 +1573,8 @@ DEFPY (show_route_detail, VRF_FULL_CMD_HELP_STR "IPv6 Address\n" "IPv6 prefix\n" - JSON_STR) + JSON_STR + "Nexthop Group Information\n") { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct route_table *table; @@ -1580,6 +1583,7 @@ DEFPY (show_route_detail, bool use_fib = !!fib; rib_dest_t *dest; bool network_found = false; + bool show_ng = !!ng; if (address_str) prefix_str = address_str; @@ -1613,10 +1617,10 @@ DEFPY (show_route_detail, network_found = true; if (json) - vty_show_ip_route_detail_json(vty, rn, - use_fib); + vty_show_ip_route_detail_json(vty, rn, use_fib); else - vty_show_ip_route_detail(vty, rn, 0, use_fib); + vty_show_ip_route_detail(vty, rn, 0, use_fib, + show_ng); route_unlock_node(rn); } @@ -1668,7 +1672,7 @@ DEFPY (show_route_detail, if (json) vty_show_ip_route_detail_json(vty, rn, use_fib); else - vty_show_ip_route_detail(vty, rn, 0, use_fib); + vty_show_ip_route_detail(vty, rn, 0, use_fib, show_ng); route_unlock_node(rn); } From 08c51a385dbe501a48536cae74fa3274e08f753c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 28 Aug 2019 14:40:16 -0400 Subject: [PATCH 161/189] zebra: Only check nexthop status on route install/update We do not need to check that the nexthop is installed or queued when sending a route deletion since we only need to the prefix for it. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 04aca1ac7e4d..dea51ded1ba6 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1534,8 +1534,13 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, /* * Check if the nhe is installed/queued before doing anything * with this route. + * + * If its a delete we only use the prefix anyway, so this only + * matters for INSTALL/UPDATE. */ - if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) + if (((op == DPLANE_OP_ROUTE_INSTALL) + || (op == DPLANE_OP_ROUTE_UPDATE)) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { ret = ENOENT; goto done; From 7d5bb02b1adf4b0e11c6e27590e0b5b3ab841baa Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 28 Aug 2019 16:15:17 -0400 Subject: [PATCH 162/189] zebra: Force off kernel nexthop group API for now Force off kernel nexthop group API for now. Will re-enable after suffient testing. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 18d1eee9e366..f6267050853a 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2449,6 +2449,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } +#if 0 /* Force off kernel nexthop group installs for now */ /** * netlink_request_nexthop() - Request nextop information from the kernel * @zns: Zebra namespace @@ -2474,6 +2475,7 @@ static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type) return netlink_request(&zns->netlink_cmd, &req.n); } + /** * netlink_nexthop_read() - Nexthop read function using netlink interface * @@ -2506,6 +2508,12 @@ int netlink_nexthop_read(struct zebra_ns *zns) return ret; } +#else +int netlink_nexthop_read(struct zebra_ns *zns) +{ + return 0; +} +#endif int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, From 62b045d6c56ef4d1edef9f19228c7e9667c0d6a7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 29 Aug 2019 10:27:31 -0400 Subject: [PATCH 163/189] zebra: Fix missed bsd nexthop group pointer When moving the nexthop group in a route entry to be a pointer, we missed one wrapped in a `ifndef` for when the kernel doesn't have netlink. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index dea51ded1ba6..d7354024aaa8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1835,7 +1835,7 @@ dplane_route_update_internal(struct route_node *rn, * We'll need these to do per-nexthop deletes. */ copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop), - old_re->ng.nexthop, NULL); + old_re->ng->nexthop, NULL); #endif /* !HAVE_NETLINK */ } From 07cc1745ff0db626e7e9adc8d18c2372de62a23d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Thu, 29 Aug 2019 11:42:52 -0400 Subject: [PATCH 164/189] zebra: Add bsd nexthop install boilerplate Add some boilerplate for nexthop installation for bsd kernels. They do not support nexthop objects for now so its just boilerplate. Signed-off-by: Stephen Worley --- zebra/rt_socket.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 981ef7a889fd..73b3dd0b406f 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -364,6 +364,11 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) return res; } +enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) +{ + return ZEBRA_DPLANE_REQUEST_SUCCESS; +} + int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, int llalen, ns_id_t ns_id) { From d7b5921c580591aca80da561aa84dc32fa4f2222 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 30 Aug 2019 16:18:07 -0400 Subject: [PATCH 165/189] zebra: Update ip route show with nexthop_num API Switch the nexthop_num dereferences to use the nexthop_group API in `vty_show_ip_route()`. Signed-off-by: Stephen Worley --- zebra/zebra_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 2ff05e4858ae..e12d16333ff8 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -466,9 +466,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "internalFlags", re->flags); json_object_int_add(json_route, "internalNextHopNum", - re->nexthop_num); + nexthop_group_nexthop_num(re->ng)); json_object_int_add(json_route, "internalNextHopActiveNum", - re->nexthop_active_num); + nexthop_group_active_nexthop_num(re->ng)); if (uptime < ONE_DAY_SECOND) sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); From 737170f5bf7e9f999543c30eff4824646885652b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 13:53:45 -0400 Subject: [PATCH 166/189] topotests: Expect shared nexthop memory A few topotests were failing since they were not aware of shared nexthops and, therefore, matching on flags that could be changed when another route sharing that nexthop is installed. Update routes that are not installed to not match their json output on the nexthop flag information. The ones that are installed will still retain their matches though since they can be sure the nexthop should have those flags (they would be the route that set them). Signed-off-by: Stephen Worley --- tests/topotests/bfd-topo2/r1/ipv6_routes.json | 1 - tests/topotests/bfd-topo2/r2/ipv4_routes.json | 1 - tests/topotests/bfd-topo2/r2/ipv6_routes.json | 1 - tests/topotests/bfd-topo2/r3/ipv4_routes.json | 1 - tests/topotests/bfd-topo2/r4/ipv6_routes.json | 1 - tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json | 1 - tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json | 1 - 7 files changed, 7 deletions(-) diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json index d09439a8a63a..0fd03b516d7f 100644 --- a/tests/topotests/bfd-topo2/r1/ipv6_routes.json +++ b/tests/topotests/bfd-topo2/r1/ipv6_routes.json @@ -33,7 +33,6 @@ { "interfaceName": "r1-eth0", "interfaceIndex": 2, - "flags": 1, "active": true, "afi": "ipv6" } diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json index 3c41e134349b..69a5f1a5bc97 100644 --- a/tests/topotests/bfd-topo2/r2/ipv4_routes.json +++ b/tests/topotests/bfd-topo2/r2/ipv4_routes.json @@ -11,7 +11,6 @@ { "active": true, "directlyConnected": true, - "flags": 1, "interfaceIndex": 3, "interfaceName": "r2-eth1" } diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json index bb45bbae5283..66abade380ef 100644 --- a/tests/topotests/bfd-topo2/r2/ipv6_routes.json +++ b/tests/topotests/bfd-topo2/r2/ipv6_routes.json @@ -11,7 +11,6 @@ { "active": true, "directlyConnected": true, - "flags": 1, "interfaceIndex": 4, "interfaceName": "r2-eth2" } diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json index cbf116e6879e..d4a0812ae16a 100644 --- a/tests/topotests/bfd-topo2/r3/ipv4_routes.json +++ b/tests/topotests/bfd-topo2/r3/ipv4_routes.json @@ -11,7 +11,6 @@ { "active": true, "directlyConnected": true, - "flags": 1, "interfaceIndex": 2, "interfaceName": "r3-eth0" } diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json index a22c90cbbaee..af8272c4aff8 100644 --- a/tests/topotests/bfd-topo2/r4/ipv6_routes.json +++ b/tests/topotests/bfd-topo2/r4/ipv6_routes.json @@ -11,7 +11,6 @@ { "active": true, "directlyConnected": true, - "flags": 1, "interfaceIndex": 2, "interfaceName": "r4-eth0" } diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json index d0378b56493f..acf5c8b276ba 100644 --- a/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json +++ b/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json @@ -10,7 +10,6 @@ { "interfaceName": "r1-eth0", "interfaceIndex": 2, - "flags": 1, "active": true, "afi": "ipv6" } diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json index 1ca62094bdfc..e5aff94bdd0d 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json @@ -10,7 +10,6 @@ "internalFlags": 0, "nexthops": [ { - "flags": 1, "afi": "ipv6", "interfaceIndex": 2, "interfaceName": "r1-eth0", From 9c387098eb147a628857982639258cf7d4d9a090 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 14:46:14 -0400 Subject: [PATCH 167/189] lib: Fix nexthop_group_equal*() NULL check Logic error on the second null check for nexthop groups passed to the `nexthop_group_equal*() functions. This fixes it. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 86c885012c83..54868d7fca78 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -142,7 +142,7 @@ bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, if (nhg1 && !nhg2) return false; - if (!nhg1 && !nhg2) + if (!nhg1 && nhg2) return false; if (nexthop_group_nexthop_num_no_recurse(nhg1) @@ -168,7 +168,7 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, if (nhg1 && !nhg2) return false; - if (!nhg1 && !nhg2) + if (!nhg1 && nhg2) return false; if (nexthop_group_nexthop_num(nhg1) != nexthop_group_nexthop_num(nhg2)) From e9f6516243f58a856bc467a2ca95730cb7cabfc7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 15:10:21 -0400 Subject: [PATCH 168/189] zebra: Fix NULL check in zebra_nhg_rib_find() Check both the nhg and nexthop are not NULL before passing them to be hashed. Clang SA caught this. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 8cc18771065b..8fb4f3357b0a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1033,15 +1033,13 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) { struct nhg_hash_entry *nhe = NULL; - vrf_id_t nhg_vrf_id = nhg->nexthop->vrf_id; - - if (!nhg) { + if (!(nhg && nhg->nexthop)) { flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, "No nexthop passed to %s", __func__); return NULL; } - zebra_nhg_find(&nhe, id, nhg, NULL, nhg_vrf_id, rt_afi, 0); + zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0); return nhe; } From fec211ad95a3a2967e72d49ab3036ae01e4b3762 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 16:12:06 -0400 Subject: [PATCH 169/189] 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(-) diff --git a/zebra/interface.c b/zebra/interface.c index 4754762b979c..76d5d2a2463a 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 f6267050853a..c24745cf1c5f 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 42d8c70f4911..331ca44c677e 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 8fb4f3357b0a..720c09397f98 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 d4abb61f22b3..337a2f09c5d9 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 e12d16333ff8..7f569cdb0eef 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); From dd9546e1966e91de0f88bdcba19c93440b8df006 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 16:43:42 -0400 Subject: [PATCH 170/189] lib: Add NULL check in nexthop_group_equal*() iter Add NULL checks in `nexthop_group_equal*()` iteration before calling `nexthop_same()` to make Clang SA happy. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 54868d7fca78..35599488bf53 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -145,12 +145,19 @@ bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, if (!nhg1 && nhg2) return false; + if (nhg1 == nhg2) + return true; + if (nexthop_group_nexthop_num_no_recurse(nhg1) != nexthop_group_nexthop_num_no_recurse(nhg2)) return false; for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2; nh1 = nh1->next, nh2 = nh2->next) { + if (nh1 && !nh2) + return false; + if (!nh1 && nh2) + return false; if (!nexthop_same(nh1, nh2)) return false; } @@ -171,11 +178,18 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, if (!nhg1 && nhg2) return false; + if (nhg1 == nhg2) + return true; + if (nexthop_group_nexthop_num(nhg1) != nexthop_group_nexthop_num(nhg2)) return false; for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2; nh1 = nexthop_next(nh1), nh2 = nexthop_next(nh2)) { + if (nh1 && !nh2) + return false; + if (!nh1 && nh2) + return false; if (!nexthop_same(nh1, nh2)) return false; } From f17f2c5d6c4321ecac68f55aeba5fbb2d04c27bb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 3 Sep 2019 16:59:57 -0400 Subject: [PATCH 171/189] lib: Add common handler for nexthop_group_equal*() Add a common handler function for the different nexthop_group_equal*() comparison functions. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 35599488bf53..7d8bcd1166c5 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -132,13 +132,12 @@ struct nexthop *nexthop_exists(const struct nexthop_group *nhg, return NULL; } -/* This assumes ordered */ -bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, - const struct nexthop_group *nhg2) +static bool +nexthop_group_equal_common(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2, + uint8_t (*nexthop_group_nexthop_num_func)( + const struct nexthop_group *nhg)) { - struct nexthop *nh1 = NULL; - struct nexthop *nh2 = NULL; - if (nhg1 && !nhg2) return false; @@ -148,8 +147,22 @@ bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, if (nhg1 == nhg2) return true; - if (nexthop_group_nexthop_num_no_recurse(nhg1) - != nexthop_group_nexthop_num_no_recurse(nhg2)) + if (nexthop_group_nexthop_num_func(nhg1) + != nexthop_group_nexthop_num_func(nhg2)) + return false; + + return true; +} + +/* This assumes ordered */ +bool nexthop_group_equal_no_recurse(const struct nexthop_group *nhg1, + const struct nexthop_group *nhg2) +{ + struct nexthop *nh1 = NULL; + struct nexthop *nh2 = NULL; + + if (!nexthop_group_equal_common(nhg1, nhg2, + &nexthop_group_nexthop_num_no_recurse)) return false; for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2; @@ -172,16 +185,7 @@ bool nexthop_group_equal(const struct nexthop_group *nhg1, struct nexthop *nh1 = NULL; struct nexthop *nh2 = NULL; - if (nhg1 && !nhg2) - return false; - - if (!nhg1 && nhg2) - return false; - - if (nhg1 == nhg2) - return true; - - if (nexthop_group_nexthop_num(nhg1) != nexthop_group_nexthop_num(nhg2)) + if (!nexthop_group_equal_common(nhg1, nhg2, &nexthop_group_nexthop_num)) return false; for (nh1 = nhg1->nexthop, nh2 = nhg2->nexthop; nh1 || nh2; From a7df21c4d23ff55f7df3d1a1caabf0040f110edf Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 6 Sep 2019 12:30:30 -0400 Subject: [PATCH 172/189] zebra: Fallback to default ns if nhg vrf lookup fails If the vrf lookup fails, use the default namespace to find/delete the nexthop group from the kernel because it should be there anyway. Signed-off-by: Stephen Worley --- zebra/zebra_dplane.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index d7354024aaa8..a88b0a38da81 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1573,6 +1573,7 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct nhg_hash_entry *nhe) { + struct zebra_vrf *zvrf = NULL; struct zebra_ns *zns = NULL; int ret = EINVAL; @@ -1597,7 +1598,13 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp( ctx->u.rinfo.nhe.nh_grp, nhe, MULTIPATH_NUM); - zns = ((struct zebra_vrf *)vrf_info_lookup(nhe->vrf_id))->zns; + zvrf = vrf_info_lookup(nhe->vrf_id); + + /* + * Fallback to default namespace if the vrf got ripped out from under + * us. + */ + zns = zvrf ? zvrf->zns : zebra_ns_lookup(NS_DEFAULT); /* * TODO: Might not need to mark this as an update, since From da3ef85b22060081cd137a74db42e79d5402fb0e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 9 Sep 2019 13:44:17 -0400 Subject: [PATCH 173/189] doc: Add docs for new nexthop group commands Add some doc information for the new nexthop group commands. Also had to add some for ones that were missing, which we are adding additional commands to. Signed-off-by: Stephen Worley --- doc/user/zebra.rst | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index af465f6fd4c7..2099dfdd62c0 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -839,11 +839,22 @@ zebra Terminal Mode Commands .. index:: show ipv6 route .. clicmd:: show ipv6 route -.. index:: show interface [{vrf VRF|brief}] -.. clicmd:: show interface [{vrf VRF|brief}] +.. index:: show [ip|ipv6] route [PREFIX] [nexthop-group] +.. clicmd:: show [ip|ipv6] route [PREFIX] [nexthop-group] -.. index:: show interface [{vrf all|brief}] -.. clicmd:: show interface [{vrf all|brief}] + Display detailed information about a route. If [nexthop-group] is + included, it will display the nexthop group ID the route is using as well. + +.. index:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group] +.. clicmd:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group] + +.. index:: show interface [NAME] [{vrf all|brief}] [nexthop-group] +.. clicmd:: show interface [NAME] [{vrf all|brief}] [nexthop-group] + + Display interface information. If no extra information is added, it will + dump information on all interfaces. If [NAME] is specified, it will display + detailed information about that single interface. If [nexthop-group] is + specified, it will display nexthop groups pointing out that interface. .. index:: show ip prefix-list [NAME] .. clicmd:: show ip prefix-list [NAME] @@ -900,3 +911,8 @@ zebra Terminal Mode Commands Reset statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. +.. index:: show nexthop-group [ID] [vrf NAME] [ip|ipv6] +.. clicmd:: show nexthop-group [ID] [vrf NAME] [ip|ipv6] + + Display nexthop groups created by zebra. + From 40a2a6cdd3f28848bedd98bfd854c73f788ab086 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 24 Sep 2019 18:38:28 -0400 Subject: [PATCH 174/189] zebra: Add DPLANE_NEIGH and DPLANE_VTEP to nhg cases Add DPLANE_OP_NEIGH and DPLANE_OP_VTEP to nhg dplane handler's switch statements. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 5 +++++ zebra/zebra_nhg.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c24745cf1c5f..4fe4d8238697 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2133,6 +2133,11 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) case DPLANE_OP_ADDR_UNINSTALL: case DPLANE_OP_MAC_INSTALL: case DPLANE_OP_MAC_DELETE: + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_VTEP_ADD: + case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NONE: flog_err( EC_ZEBRA_NHG_FIB_UPDATE, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 720c09397f98..c22ed67f8071 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1916,6 +1916,11 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_ADDR_UNINSTALL: case DPLANE_OP_MAC_INSTALL: case DPLANE_OP_MAC_DELETE: + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_VTEP_ADD: + case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NONE: break; } From b2665a211ed7436dbcd4b477f628c2cdf546c2ca Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 24 Sep 2019 18:40:09 -0400 Subject: [PATCH 175/189] zebra: Use ng pointer in mpls_ftn_uninstall With the new nexthop group shared memory framework, pointers are being used in route_entry for the nexthop_group. Update the use of this in `mpls_ftn_uninstall()` to reflect the change. Signed-off-by: Stephen Worley --- zebra/zebra_mpls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 331ca44c677e..ef1bd02608be 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2698,7 +2698,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) nexthop_del_labels(nexthop); SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); From cd36b87d8c067626dce566143e7998d0a0a9b722 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 13:54:39 -0400 Subject: [PATCH 176/189] pbrd: nexthop_group delete cb don't free pbr->nhg The pbr->nhg callback is used exclusively for individual nexthops set through `set nexthop`. If an actuall "tracked" nexthop_group is used, only the `pbrms->nhgrp_name` is set. Thus this delete does nothing. Signed-off-by: Stephen Worley --- pbrd/pbr_nht.c | 1 - 1 file changed, 1 deletion(-) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 67a1fe2ffe86..062cfd0158b6 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -639,7 +639,6 @@ void pbr_nht_delete_group(const char *name) if (pbrms->nhgrp_name && strmatch(pbrms->nhgrp_name, name)) { pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; - nexthop_group_delete(&pbrms->nhg); pbrms->nhg = NULL; pbrms->internal_nhg_name = NULL; pbrm->valid = false; From d3a35138115f89c19d0c44776da705b52975909f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 14:04:43 -0400 Subject: [PATCH 177/189] 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(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 7d8bcd1166c5..9552f895683b 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 378b0ce6bb71..391775c69c39 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 062cfd0158b6..7ccd14d1f1b7 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 ab4c246d166f..d6ade783cf0f 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 c22ed67f8071..f4fc06efc953 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 337a2f09c5d9..e0bf1a58f244 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 af3c1b818f2f..60e23cc4d480 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); } From 53ac1fbbe05665005f83a802ebe302e21dec720e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 14:28:33 -0400 Subject: [PATCH 178/189] zebra: Comment to indicate where nhg hashtables live Add a comment to the header of `zebra_nhg.c` to point the reader to where the hashtables containing the nhg entries are held. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 812d9a1a90e8..d3c63cff3035 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -41,6 +41,11 @@ struct nh_grp { PREDECL_RBTREE_UNIQ(nhg_connected_tree); + +/* + * Hashtables contiaining entries found in `zebra_router`. + */ + struct nhg_hash_entry { uint32_t id; afi_t afi; From fefa080e3c6667db48a749015b4590951ef17e10 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 14:32:26 -0400 Subject: [PATCH 179/189] zebra: Remove cleanup and nhg workqueue boilerplate This code was from a strategies we elected not to use and can safely be removed. Signed-off-by: Stephen Worley --- zebra/main.c | 1 - zebra/zebra_nhg.c | 19 ------------------- zebra/zebra_nhg.h | 5 ----- zebra/zebra_router.c | 11 ----------- 4 files changed, 36 deletions(-) diff --git a/zebra/main.c b/zebra/main.c index e57b84c8f6f7..334354eaae87 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -166,7 +166,6 @@ static void sigint(void) if (zrouter.lsp_process_q) work_queue_free_and_null(&zrouter.lsp_process_q); - zebra_router_cleanup(); vrf_terminate(); ns_walk_func(zebra_ns_early_shutdown); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index f4fc06efc953..44524ec507c5 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1834,25 +1834,6 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) zebra_nhg_handle_uninstall(nhe); } -static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg) -{ - struct nhg_hash_entry *nhe = NULL; - - nhe = (struct nhg_hash_entry *)bucket->data; - - if (ZEBRA_NHG_CREATED(nhe)) - zebra_nhg_uninstall_kernel(nhe); -} - -void zebra_nhg_cleanup_tables(struct hash *hash) -{ - /* - * TODO: These should only be uninstalled via route cleanup path? - */ - return; - hash_iterate(hash, zebra_nhg_uninstall_created, NULL); -} - void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) { enum dplane_op_e op; diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index d3c63cff3035..e5eb51862880 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -169,9 +169,6 @@ struct nhg_ctx { }; -void zebra_nhg_init(void); -void zebra_nhg_terminate(void); - extern void nhg_connected_free(struct nhg_connected *dep); extern struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe); @@ -263,8 +260,6 @@ 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(struct hash *hash); - /* Forward ref of dplane update context type */ struct zebra_dplane_ctx; void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index d6ec6ac1658e..f52249ad8b2b 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -271,14 +271,3 @@ void zebra_router_init(void) hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal, "Zebra Router Nexthop Groups ID index"); } - -/** - * zebra_router_cleanup() - Perform any cleanup actions before termination - * - * Right now this is just being used to clear the nexthops we installed in - * the kernel on shutdown before the routes are cleaned via vrf_terminated(). - */ -void zebra_router_cleanup(void) -{ - zebra_nhg_cleanup_tables(zrouter.nhgs_id); -} From 724583edaddffda86498967ba51297fa6adcb653 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 16:12:19 -0400 Subject: [PATCH 180/189] zebra: Set the nhe type in the appropriate place We were setting the nhe type on uninstall when it should be on the install. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 44524ec507c5..da6c2c26c60f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1786,6 +1786,9 @@ 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)) { + /* Change its type to us since we are installing it */ + nhe->type = ZEBRA_ROUTE_NHG; + int ret = dplane_nexthop_add(nhe); switch (ret) { @@ -1813,8 +1816,6 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { int ret = dplane_nexthop_delete(nhe); - /* Change its type to us since we are installing it */ - nhe->type = ZEBRA_ROUTE_NHG; switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); From 177e711dfc119098e982cc3d16d4a6bd123a77a6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 4 Oct 2019 16:48:20 -0400 Subject: [PATCH 181/189] zebra: Adjust nhg handling for dataplane result off on shutdown Now with this patch we can't use shutdown for cleanup: ``` commit 2fc69f03d2f49fcf34948e82e865cd302ae08da0 (pr_5079) Author: Mark Stapp Date: Fri Sep 27 12:15:34 2019 -0400 zebra: during shutdown processing, drop dplane results Don't process dataplane results in zebra during shutdown (after sigint has been seen). The dplane continues to run in order to clean up, but zebra main just drops results. Signed-off-by: Mark Stapp ``` Adjusted nhg uninstall handling to clear data and other cleanup before sending to the dataplane. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 145 ++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 82 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index da6c2c26c60f..38ff7c60de37 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -686,13 +686,7 @@ static void zebra_nhg_set_dup(struct nhg_hash_entry *nhe) nhe->id); } -/* - * 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) +static void zebra_nhg_release(struct nhg_hash_entry *nhe) { /* Remove it from any lists it may be on */ zebra_nhg_depends_release(nhe); @@ -706,17 +700,13 @@ static void zebra_nhg_release_no_id(struct nhg_hash_entry *nhe) */ if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE)) hash_release(zrouter.nhgs, nhe); -} -static void zebra_nhg_release_id(struct nhg_hash_entry *nhe) -{ hash_release(zrouter.nhgs_id, nhe); } - static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe) { - zebra_nhg_release_id(nhe); + zebra_nhg_release(nhe); zebra_nhg_free(nhe); } @@ -735,10 +725,8 @@ static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe, UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); zebra_nhg_install_kernel(nhe); - } else { - zebra_nhg_release_no_id(nhe); + } else zebra_nhg_handle_uninstall(nhe); - } } static int nhg_ctx_process_new(struct nhg_ctx *ctx) @@ -1810,9 +1798,6 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *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); @@ -1828,11 +1813,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_handle_uninstall(nhe); break; } - } else - zebra_nhg_handle_uninstall(nhe); + } + + zebra_nhg_handle_uninstall(nhe); } void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) @@ -1847,70 +1832,66 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) id = dplane_ctx_get_nhe_id(ctx); - nhe = zebra_nhg_lookup_id(id); + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug( + "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", + ctx, dplane_op2str(op), id, dplane_res2str(status)); - if (nhe) { - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) - zlog_debug( - "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", - ctx, dplane_op2str(op), nhe->id, - dplane_res2str(status)); - - switch (op) { - case DPLANE_OP_NH_DELETE: - if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_handle_uninstall(nhe); - } else { - flog_err( - EC_ZEBRA_DP_DELETE_FAIL, - "Failed to uninstall Nexthop ID (%u) from the kernel", - nhe->id); - } - break; - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - } else { - flog_err( - EC_ZEBRA_DP_INSTALL_FAIL, - "Failed to install Nexthop ID (%u) into the kernel", - nhe->id); - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - } - break; - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_NONE: + switch (op) { + case DPLANE_OP_NH_DELETE: + if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) + flog_err( + EC_ZEBRA_DP_DELETE_FAIL, + "Failed to uninstall Nexthop ID (%u) from the kernel", + id); + /* We already free'd the data, nothing to do */ + break; + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + nhe = zebra_nhg_lookup_id(id); + + if (!nhe) { + flog_err( + EC_ZEBRA_NHG_SYNC, + "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table", + dplane_op2str(op), id); break; } - } else - flog_err( - EC_ZEBRA_NHG_SYNC, - "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table", - dplane_op2str(op), id); + + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); + if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } else + flog_err( + EC_ZEBRA_DP_INSTALL_FAIL, + "Failed to install Nexthop ID (%u) into the kernel", + nhe->id); + break; + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_VTEP_ADD: + case DPLANE_OP_VTEP_DELETE: + case DPLANE_OP_NONE: + break; + } dplane_ctx_fini(&ctx); } From 5a935f79d5c6990b899862de6e3022036e4a7ffa Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 13:08:10 -0400 Subject: [PATCH 182/189] zebra: Guard nexthop group overflow read Guard against an overflow read when processing nexthop groups from netlink. Add a check to ensure we don't try to write passed the array size. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4fe4d8238697..b5ddc954c3ac 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2313,7 +2313,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, } static int netlink_nexthop_process_group(struct rtattr **tb, - struct nh_grp *z_grp) + struct nh_grp *z_grp, int z_grp_size) { uint8_t count = 0; /* linux/nexthop.h group struct */ @@ -2335,7 +2335,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, #endif - for (int i = 0; i < count; i++) { + for (int i = 0; ((i < count) && (i < z_grp_size)); i++) { z_grp[i].id = n_grp[i].id; z_grp[i].weight = n_grp[i].weight; } @@ -2412,7 +2412,8 @@ 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 */ - grp_count = netlink_nexthop_process_group(tb, grp); + grp_count = netlink_nexthop_process_group( + tb, grp, array_size(grp)); } else { if (tb[NHA_BLACKHOLE]) { /** From 0b4dadb3858667a858c20aac9c6b854aaf2ebdf9 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 14:08:12 -0400 Subject: [PATCH 183/189] zebra: Check depends for validity, not dependents When determining whether to set the nhg_hash_entry as invalid, we should have been checking the depends, not the dependents. If its a group and at least one of its depends is valid, the group is still valid. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 38ff7c60de37..9afecbd90914 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1081,8 +1081,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, - rb_node_dep) { + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) return; From 17c25e0368e765ec23b7c94e65f5d4e44102f77e Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 14:37:20 -0400 Subject: [PATCH 184/189] lib: Make nexthop_next* use const for nexthop Make nexthop_next() and nexthop_next_active_resolved() use const for the nexthop argument. They should not be modifying so it makes sense here. Signed-off-by: Stephen Worley --- lib/nexthop.c | 4 ++-- lib/nexthop.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 017131882725..73c2de0cd80e 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -349,7 +349,7 @@ const char *nexthop2str(const struct nexthop *nexthop, char *str, int size) * left branch is 'resolved' and right branch is 'next': * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg */ -struct nexthop *nexthop_next(struct nexthop *nexthop) +struct nexthop *nexthop_next(const struct nexthop *nexthop) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) return nexthop->resolved; @@ -365,7 +365,7 @@ struct nexthop *nexthop_next(struct nexthop *nexthop) } /* Return the next nexthop in the tree that is resolved and active */ -struct nexthop *nexthop_next_active_resolved(struct nexthop *nexthop) +struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop) { struct nexthop *next = nexthop_next(nexthop); diff --git a/lib/nexthop.h b/lib/nexthop.h index 480c4cc3dd69..fe029f186793 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -161,8 +161,9 @@ 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_next_active_resolved(struct nexthop *nexthop); +extern struct nexthop *nexthop_next(const struct nexthop *nexthop); +extern struct nexthop * +nexthop_next_active_resolved(const 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, From c1da832a948af638c3edd88fc3e5e5a5b5b3248c Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 14:50:30 -0400 Subject: [PATCH 185/189] zebra: Change wording of duplicate kernel nhg flag Change the wording of the flag indicating we have received a nexthop group from the kernel with a different ID but is fundamentally identical to one we already have. It was colliding with a flag of similar name in the nexthop struct. Change it from NEXTHOP_GROUP_DUPLICATE -> NEXTHOP_GROUP_UNHASHABLE since it is in fact unhashable. Also change the wording of functions and comments referencing the same problem. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 34 ++++++++++++++++++---------------- zebra/zebra_nhg.h | 9 ++++++--- zebra/zebra_vty.c | 2 +- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9afecbd90914..1b9440218b66 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -663,27 +663,28 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, return ctx; } -static bool zebra_nhg_contains_dup(struct nhg_hash_entry *nhe) +static bool zebra_nhg_contains_unhashable(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)) + NEXTHOP_GROUP_UNHASHABLE)) return true; } return false; } -static void zebra_nhg_set_dup(struct nhg_hash_entry *nhe) +static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe) { - SET_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE); 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); + flog_warn( + EC_ZEBRA_DUPLICATE_NHG_MESSAGE, + "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring", + nhe->id); } static void zebra_nhg_release(struct nhg_hash_entry *nhe) @@ -695,10 +696,10 @@ static void zebra_nhg_release(struct nhg_hash_entry *nhe) if_nhg_dependents_del(nhe->ifp, nhe); /* - * If its a dup, we didn't store it here and have to be + * If its unhashable, 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)) + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE)) hash_release(zrouter.nhgs, nhe); hash_release(zrouter.nhgs_id, nhe); @@ -786,19 +787,20 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) * changes. * * We maintain them *ONLY* in the ID hash table to - * track them. + * track them and set the flag to indicated + * their attributes are unhashable. */ kernel_nhe = zebra_nhg_copy(nhe, 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. + zebra_nhg_set_unhashable(kernel_nhe); + } else if (zebra_nhg_contains_unhashable(nhe)) { + /* The group we got contains an unhashable/duplicated + * depend, so lets mark this group as unhashable as well + * and release it from the non-ID hash. */ hash_release(zrouter.nhgs, nhe); - zebra_nhg_set_dup(nhe); + zebra_nhg_set_unhashable(nhe); } else { /* It actually created a new nhe */ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index e5eb51862880..82f54a3a63f3 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -99,10 +99,13 @@ struct nhg_hash_entry { */ #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. + * This is a nexthop group we got from the kernel, it is identical to + * one we already have. (The kernel allows duplicate nexthops, we don't + * since we hash on them). We are only tracking it in our ID table, + * it is unusable by our created routes but may be used by routes we get + * from the kernel. Therefore, it is unhashable. */ -#define NEXTHOP_GROUP_DUPLICATE (1 << 4) +#define NEXTHOP_GROUP_UNHASHABLE (1 << 4) }; /* Was this one we created, either this session or previously? */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7f569cdb0eef..9d174547305e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1122,7 +1122,7 @@ 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_UNHASHABLE)) vty_out(vty, " Duplicate - from kernel not hashable\n"); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { From e1292378e242735f25a4073119ca2da897100fc8 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 15:07:22 -0400 Subject: [PATCH 186/189] zebra: Improve commenting for group requeue case The commenting for why we would need to requeue a group from the kernel to be later processed was not sufficient. Add a better explanation for the flow and state of the system. Signed-off-by: Stephen Worley --- zebra/zebra_nhg.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1b9440218b66..418c1102bdb0 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -883,10 +883,17 @@ int nhg_ctx_process(struct nhg_ctx *ctx) ret = nhg_ctx_process_new(ctx); if (nhg_ctx_get_count(ctx) && ret == -ENOENT && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) { - /* Depends probably came before group, re-queue. + /** + * We have entered a situation where we are + * processing a group from the kernel + * that has a contained nexthop which + * we have not yet processed. * - * Only going to retry once, hence just using status - * flag rather than counter. + * Re-enqueue this ctx to be handled exactly one + * more time (indicated by the flag). + * + * By the time we get back to it, we + * should have processed its depends. */ nhg_ctx_set_status(ctx, NHG_CTX_NONE); if (queue_add(ctx) == 0) { From 80286aa564601dda7430ea8c96b2f9fd9867ee0b Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 16:49:07 -0400 Subject: [PATCH 187/189] zebra: Re-work zebra_nhg_*_valid APIs Re-work the validity setting and checking APIs for nhg_hash_entry's to make them clearer. Further, they were originally only beings set on ifdown and install. Extended their use into releasing entries and to account for setting the validity of a recursive dependent. Signed-off-by: Stephen Worley --- zebra/interface.c | 45 +++++++++++------------ zebra/zebra_nhg.c | 92 +++++++++++++++++++++++++++++------------------ zebra/zebra_nhg.h | 2 +- 3 files changed, 82 insertions(+), 57 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 76d5d2a2463a..daa93e36d1c4 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -189,17 +189,31 @@ static int if_zebra_new_hook(struct interface *ifp) return 0; } -static void if_nhg_dependents_release(struct interface *ifp) +static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe) { - if (!if_nhg_dependents_is_empty(ifp)) { - struct nhg_connected *rb_node_dep = NULL; - struct zebra_if *zif = (struct zebra_if *)ifp->info; + zebra_nhg_check_valid(nhe); + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) + /* Assuming uninstalled as well here */ + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); +} - 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); - } +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, rb_node_dep) + if_nhg_dependents_check_valid(rb_node_dep->nhe); +} + +static void if_nhg_dependents_release(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, rb_node_dep) { + rb_node_dep->nhe->ifp = NULL; /* Null it out */ + if_nhg_dependents_check_valid(rb_node_dep->nhe); } } @@ -998,19 +1012,6 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp) return false; } -static void if_down_nhg_dependents(const 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; - - frr_each(nhg_connected_tree, &zif->nhg_dependents, - rb_node_dep) { - zebra_nhg_set_invalid(rb_node_dep->nhe); - } - } -} - /* Interface is up. */ void if_up(struct interface *ifp) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 418c1102bdb0..3ec764c5d390 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -246,13 +246,12 @@ void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe) /* Release this nhe from anything depending on it */ 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; + struct nhg_connected *rb_node_dep = NULL; - frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, - rb_node_dep) { - zebra_nhg_depends_del(rb_node_dep->nhe, nhe); - } + frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { + zebra_nhg_depends_del(rb_node_dep->nhe, nhe); + /* recheck validity of the dependent */ + zebra_nhg_check_valid(rb_node_dep->nhe); } } @@ -687,6 +686,48 @@ static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe) nhe->id); } +static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe) +{ + struct nhg_connected *rb_node_dep; + + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + + frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) + zebra_nhg_set_valid(rb_node_dep->nhe); +} + +static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) +{ + struct nhg_connected *rb_node_dep; + + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + + /* Update validity of nexthops depending on it */ + frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) + zebra_nhg_check_valid(rb_node_dep->nhe); +} + +void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) +{ + struct nhg_connected *rb_node_dep = NULL; + bool valid = false; + + /* If anthing else in the group is valid, the group is valid */ + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) { + valid = true; + goto done; + } + } + +done: + if (valid) + zebra_nhg_set_valid(nhe); + else + zebra_nhg_set_invalid(nhe); +} + + static void zebra_nhg_release(struct nhg_hash_entry *nhe) { /* Remove it from any lists it may be on */ @@ -711,6 +752,15 @@ static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe) zebra_nhg_free(nhe); } +static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe) +{ + /* Update validity of groups depending on it */ + struct nhg_connected *rb_node_dep; + + frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) + zebra_nhg_set_valid(rb_node_dep->nhe); +} + /* * The kernel/other program has changed the state of a nexthop object we are * using. @@ -1083,34 +1133,6 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) nhg_connected_tree_increment_ref(&nhe->nhg_depends); } -void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) -{ - if (!zebra_nhg_depends_is_empty(nhe) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) { - 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_depends, rb_node_dep) { - if (CHECK_FLAG(rb_node_dep->nhe->flags, - NEXTHOP_GROUP_VALID)) - return; - } - } - - 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; - - frr_each(nhg_connected_tree, &nhe->nhg_dependents, - rb_node_dep) { - zebra_nhg_set_invalid(rb_node_dep->nhe); - } - } -} - void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) { nhe->ifp = ifp; @@ -1799,6 +1821,7 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) break; case ZEBRA_DPLANE_REQUEST_SUCCESS: SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_handle_install(nhe); break; } } @@ -1870,6 +1893,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_handle_install(nhe); } else flog_err( EC_ZEBRA_DP_INSTALL_FAIL, diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 82f54a3a63f3..e636c0f2d2ea 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -249,7 +249,7 @@ void zebra_nhg_free(void *arg); 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_check_valid(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); From 5948f013ba454431295d4016b17f01952e4663f2 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 23 Oct 2019 18:28:10 -0400 Subject: [PATCH 188/189] zebra: Cleanup zebra_nhg APIs Add a private header file for functions that are internal/special case like how we do it for `lib/nexthop_group_private.h`. Remove a bunch of functions from the header file only being used statically and add some comments for those remaining to indicate better what their use is. Signed-off-by: Stephen Worley --- zebra/interface.h | 2 +- zebra/subdir.am | 1 + zebra/zebra_nhg.c | 96 +++++++++++++++------------------------ zebra/zebra_nhg.h | 83 ++++++++------------------------- zebra/zebra_nhg_private.h | 62 +++++++++++++++++++++++++ zebra/zebra_router.c | 2 +- 6 files changed, 121 insertions(+), 125 deletions(-) create mode 100644 zebra/zebra_nhg_private.h diff --git a/zebra/interface.h b/zebra/interface.h index c6f0e465fcf1..78ccbae6235d 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -27,7 +27,7 @@ #include "hook.h" #include "zebra/zebra_l2.h" -#include "zebra/zebra_nhg.h" +#include "zebra/zebra_nhg_private.h" #ifdef __cplusplus extern "C" { diff --git a/zebra/subdir.am b/zebra/subdir.am index 25040a2717dd..28847ce09b8f 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -137,6 +137,7 @@ noinst_HEADERS += \ zebra/zebra_mpls.h \ zebra/zebra_mroute.h \ zebra/zebra_nhg.h \ + zebra/zebra_nhg_private.h \ zebra/zebra_ns.h \ zebra/zebra_pbr.h \ zebra/zebra_ptm.h \ diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3ec764c5d390..2bb117b2729d 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -32,7 +32,7 @@ #include "zebra/connected.h" #include "zebra/debug.h" #include "zebra/zebra_router.h" -#include "zebra/zebra_nhg.h" +#include "zebra/zebra_nhg_private.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" #include "zebra/zebra_memory.h" @@ -60,12 +60,12 @@ depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id); static void depends_decrement_free(struct nhg_connected_tree_head *head); -void nhg_connected_free(struct nhg_connected *dep) +static void nhg_connected_free(struct nhg_connected *dep) { XFREE(MTYPE_NHG_CONNECTED, dep); } -struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) +static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe) { struct nhg_connected *new = NULL; @@ -156,26 +156,6 @@ struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *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_tree_count(&nhe->nhg_depends); @@ -186,59 +166,41 @@ bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe) return nhg_connected_tree_is_empty(&nhe->nhg_depends); } -void zebra_nhg_depends_del(struct nhg_hash_entry *from, - struct nhg_hash_entry *depend) +static void zebra_nhg_depends_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *depend) { nhg_connected_tree_del_nhe(&from->nhg_depends, depend); } -void zebra_nhg_depends_add(struct nhg_hash_entry *to, - struct nhg_hash_entry *depend) -{ - nhg_connected_tree_add_nhe(&to->nhg_depends, depend); -} - -void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) +static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe) { nhg_connected_tree_init(&nhe->nhg_depends); } -/* Release this nhe from anything that it depends on */ -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, - rb_node_dep) { - zebra_nhg_dependents_del(rb_node_dep->nhe, nhe); - } - } -} - unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe) { return nhg_connected_tree_count(&nhe->nhg_dependents); } + bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe) { return nhg_connected_tree_is_empty(&nhe->nhg_dependents); } -void zebra_nhg_dependents_del(struct nhg_hash_entry *from, - struct nhg_hash_entry *dependent) +static void zebra_nhg_dependents_del(struct nhg_hash_entry *from, + struct nhg_hash_entry *dependent) { nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent); } -void zebra_nhg_dependents_add(struct nhg_hash_entry *to, - struct nhg_hash_entry *dependent) +static void zebra_nhg_dependents_add(struct nhg_hash_entry *to, + struct nhg_hash_entry *dependent) { nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent); } -void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe) +static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe) { nhg_connected_tree_init(&nhe->nhg_dependents); } @@ -255,6 +217,20 @@ static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe) } } +/* Release this nhe from anything that it depends on */ +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, + rb_node_dep) { + zebra_nhg_dependents_del(rb_node_dep->nhe, nhe); + } + } +} + + struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id) { struct nhg_hash_entry lookup = {}; @@ -263,7 +239,7 @@ struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id) return hash_lookup(zrouter.nhgs_id, &lookup); } -int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) +static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) { if (hash_lookup(zrouter.nhgs_id, nhe)) { flog_err( @@ -278,6 +254,12 @@ int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) return 0; } +static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) +{ + nhe->ifp = ifp; + if_nhg_dependents_add(ifp, nhe); +} + static void zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, struct nhg_connected_tree_head nhg_depends) @@ -529,7 +511,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, lookup.nhg_depends = *nhg_depends; else { if (nhg->nexthop->next) { - nhg_connected_tree_init(&lookup.nhg_depends); + zebra_nhg_depends_init(&lookup); /* If its a group, create a dependency tree */ struct nexthop *nh = NULL; @@ -539,7 +521,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, nh, afi); } else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { - nhg_connected_tree_init(&lookup.nhg_depends); + zebra_nhg_depends_init(&lookup); handle_recursive_depend(&lookup.nhg_depends, nhg->nexthop->resolved, afi); @@ -1091,7 +1073,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) return nhe; } -void zebra_nhg_free_members(struct nhg_hash_entry *nhe) +static void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { nexthop_group_delete(&nhe->nhg); /* Decrement to remove connection ref */ @@ -1133,12 +1115,6 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) nhg_connected_tree_increment_ref(&nhe->nhg_depends); } -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 e636c0f2d2ea..1f695433c968 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -41,7 +41,6 @@ struct nh_grp { PREDECL_RBTREE_UNIQ(nhg_connected_tree); - /* * Hashtables contiaining entries found in `zebra_router`. */ @@ -111,21 +110,6 @@ struct nhg_hash_entry { /* 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; - struct nhg_hash_entry *nhe; -}; - -static int nhg_connected_cmp(const struct nhg_connected *con1, - const struct nhg_connected *con2) -{ - return (con1->nhe->id - con2->nhe->id); -} - -DECLARE_RBTREE_UNIQ(nhg_connected_tree, struct nhg_connected, tree_item, - nhg_connected_cmp); - enum nhg_ctx_op_e { NHG_CTX_OP_NONE = 0, @@ -172,52 +156,23 @@ struct nhg_ctx { }; -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_tree_init(struct nhg_connected_tree_head *head); -extern void nhg_connected_tree_free(struct nhg_connected_tree_head *head); -extern bool -nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head); -extern struct nhg_connected * -nhg_connected_tree_root(struct nhg_connected_tree_head *head); -extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head, - struct nhg_hash_entry *nhe); -extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head, - struct nhg_hash_entry *nhe); - /** * 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); -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_init(struct nhg_hash_entry *nhe); -/* 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); - +/* Lookup ID, doesn't create */ extern struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id); -extern int zebra_nhg_insert_id(struct nhg_hash_entry *nhe); +/* Hash functions */ extern uint32_t zebra_nhg_hash_key(const void *arg); extern uint32_t zebra_nhg_id_key(const void *arg); @@ -243,29 +198,31 @@ extern int zebra_nhg_kernel_del(uint32_t id); 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); -void zebra_nhg_free(void *arg); -void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); -void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); - -void zebra_nhg_check_valid(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); - +/* Reference counter functions */ +extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); +extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); extern int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *nhe); +/* Check validity of nhe, if invalid will update dependents as well */ +extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe); + +/* Convert nhe depends to a grp context that can be passed around safely */ extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int size); -void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); -void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); +/* Dataplane install/uninstall */ +extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); +extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); /* Forward ref of dplane update context type */ struct zebra_dplane_ctx; -void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx); +extern void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx); + -void zebra_nhg_sweep_table(struct hash *hash); +/* Sweet the nhg hash tables for old entries on restart */ +extern void zebra_nhg_sweep_table(struct hash *hash); + +/* Nexthop resolution processing */ +extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); #endif diff --git a/zebra/zebra_nhg_private.h b/zebra/zebra_nhg_private.h new file mode 100644 index 000000000000..170e2357e3a3 --- /dev/null +++ b/zebra/zebra_nhg_private.h @@ -0,0 +1,62 @@ +/* + * Nexthop Group Private Functions. + * Copyright (C) 2019 Cumulus Networks, Inc. + * Stephen Worley + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * These functions should only be used internally for nhg_hash_entry + * manipulation and in certain special cases. + * + * Please use `zebra/zebra_nhg.h` for any general nhg_hash_entry api needs. + */ + +#ifndef __ZEBRA_NHG_PRIVATE_H__ +#define __ZEBRA_NHG_PRIVATE_H__ + +#include "zebra/zebra_nhg.h" + +/* Abstraction for connected trees */ +struct nhg_connected { + struct nhg_connected_tree_item tree_item; + struct nhg_hash_entry *nhe; +}; + +static int nhg_connected_cmp(const struct nhg_connected *con1, + const struct nhg_connected *con2) +{ + return (con1->nhe->id - con2->nhe->id); +} + +DECLARE_RBTREE_UNIQ(nhg_connected_tree, struct nhg_connected, tree_item, + nhg_connected_cmp); + +/* nhg connected tree direct access functions */ +extern void nhg_connected_tree_init(struct nhg_connected_tree_head *head); +extern void nhg_connected_tree_free(struct nhg_connected_tree_head *head); +extern bool +nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head); +extern struct nhg_connected * +nhg_connected_tree_root(struct nhg_connected_tree_head *head); +extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head, + struct nhg_hash_entry *nhe); +extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head, + struct nhg_hash_entry *nhe); + +extern void zebra_nhg_free(void *arg); + +#endif /* __ZEBRA_NHG_PRIVATE_H__ */ diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index f52249ad8b2b..e5319c64af03 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -29,7 +29,7 @@ #include "zebra_pbr.h" #include "zebra_vxlan.h" #include "zebra_mlag.h" -#include "zebra_nhg.h" +#include "zebra_nhg_private.h" #include "debug.h" DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info") From f3354e1612197b9e72ef47b18979b0a5e9db0feb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 25 Oct 2019 11:11:06 -0400 Subject: [PATCH 189/189] zebra: rt_netlink nexthop handling checkpatch Checkpatch was complaining because this code was extending beyond 80 characters on a couple lines. Adjusted a conditional tree to fix that. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b5ddc954c3ac..640802fe316c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -452,23 +452,20 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, } } - 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); - } + if (gate && 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 (gate && 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);