From 5e1b0650de10973decb57385b02e0a0b7d5045d0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 16 May 2018 19:24:22 -0400 Subject: [PATCH 1/3] zebra: Convert zrmac->host_list list to a RB Tree The host_list when we attempt to use it at scale, ends up spending a non-trivial amount of time finding and sorting entries for the host list. Convert to a rb tree. Signed-off-by: Donald Sharp --- zebra/zebra_vxlan.c | 118 +++++++++++++++++++++++++++++------- zebra/zebra_vxlan_private.h | 11 +++- 2 files changed, 107 insertions(+), 22 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 3278c86b99..7cdb790358 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -56,7 +56,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); /* definitions */ - /* static function declarations */ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, uint16_t cmd); @@ -183,6 +182,48 @@ static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, int uninstall); /* Private functions */ +static int host_rb_entry_compare(const struct host_rb_entry *hle1, + const struct host_rb_entry *hle2) +{ + if (hle1->p.family < hle2->p.family) + return -1; + + if (hle1->p.family > hle2->p.family) + return 1; + + if (hle1->p.prefixlen < hle2->p.prefixlen) + return -1; + + if (hle1->p.prefixlen > hle2->p.prefixlen) + return 1; + + if (hle1->p.family == AF_INET) { + if (hle1->p.u.prefix4.s_addr < hle2->p.u.prefix4.s_addr) + return -1; + + if (hle1->p.u.prefix4.s_addr > hle2->p.u.prefix4.s_addr) + return 1; + + return 0; + } else { + zlog_warn("%s: Unexpected family type: %d", __PRETTY_FUNCTION__, + hle1->p.family); + return 0; + } +} +RB_GENERATE(host_rb_entry_rb, host_rb_entry, hl_entry, + host_rb_entry_compare); + +static uint32_t zrmac_host_count(zebra_mac_t *zrmac) +{ + struct host_rb_entry *hle; + uint32_t count = 0; + + RB_FOREACH (hle, host_rb_entry_rb, &zrmac->host_rb) + count++; + + return count; +} /* * Return number of valid MACs in a VNI's MAC hash table - all @@ -471,20 +512,19 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, { char buf1[ETHER_ADDR_STRLEN]; char buf2[PREFIX_STRLEN]; - struct listnode *node = NULL; - struct prefix *p = NULL; json_object *json_hosts = NULL; + struct host_rb_entry *hle; if (!json) { vty_out(vty, "MAC: %s\n", prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); vty_out(vty, " Remote VTEP: %s\n", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); - vty_out(vty, " Refcount: %d\n", listcount(zrmac->host_list)); + vty_out(vty, " Refcount: %d\n", zrmac_host_count(zrmac)); vty_out(vty, " Prefixes:\n"); - for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p)) + RB_FOREACH (hle, host_rb_entry_rb, &zrmac->host_rb) vty_out(vty, " %s\n", - prefix2str(p, buf2, sizeof(buf2))); + prefix2str(&hle->p, buf2, sizeof(buf2))); } else { json_hosts = json_object_new_array(); json_object_string_add( @@ -492,12 +532,12 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); json_object_string_add(json, "vtepIp", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); - json_object_int_add(json, "refCount", - listcount(zrmac->host_list)); - for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p)) - json_object_array_add(json_hosts, - json_object_new_string(prefix2str( - p, buf2, sizeof(buf2)))); + json_object_int_add(json, "refCount", zrmac_host_count(zrmac)); + RB_FOREACH (hle, host_rb_entry_rb, &zrmac->host_rb) + json_object_array_add( + json_hosts, + json_object_new_string(prefix2str( + &hle->p, buf2, sizeof(buf2)))); json_object_object_add(json, "prefixList", json_hosts); } } @@ -3042,6 +3082,39 @@ static void zl3vni_cleanup_all(struct hash_backet *backet, void *args) zebra_vxlan_process_l3vni_oper_down(zl3vni); } +static void zrmac_find_or_add_host(zebra_mac_t *zrmac, struct prefix *host) +{ + struct host_rb_entry lookup; + struct host_rb_entry *hle; + + memset(&lookup, 0, sizeof(lookup)); + memcpy(&lookup.p, host, sizeof(*host)); + + hle = RB_FIND(host_rb_entry_rb, &zrmac->host_rb, &lookup); + if (hle) + return; + + hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry)); + memcpy(hle, &lookup, sizeof(lookup)); + + RB_INSERT(host_rb_entry_rb, &zrmac->host_rb, hle); +} + +static void zrmac_delete_host(zebra_mac_t *zrmac, struct prefix *host) +{ + struct host_rb_entry lookup; + struct host_rb_entry *hle; + + memset(&lookup, 0, sizeof(lookup)); + memcpy(&lookup.p, host, sizeof(*host)); + + hle = RB_FIND(host_rb_entry_rb, &zrmac->host_rb, &lookup); + if (hle) + RB_REMOVE(host_rb_entry_rb, &zrmac->host_rb, hle); + + return; +} + static int is_host_present_in_host_list(struct list *list, struct prefix *host) { struct listnode *node = NULL; @@ -3123,8 +3196,7 @@ static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc); assert(zrmac); - zrmac->host_list = list_new(); - zrmac->host_list->cmp = (int (*)(void *, void *))prefix_cmp; + RB_INIT(host_rb_entry_rb, &zrmac->host_rb); SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE); SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC); @@ -3138,10 +3210,14 @@ static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { zebra_mac_t *tmp_rmac; + struct host_rb_entry *hle; - if (zrmac->host_list) - list_delete_and_null(&zrmac->host_list); - zrmac->host_list = NULL; + while (!RB_EMPTY(host_rb_entry_rb, &zrmac->host_rb)) { + hle = RB_ROOT(host_rb_entry_rb, &zrmac->host_rb); + + RB_REMOVE(host_rb_entry_rb, &zrmac->host_rb, hle); + XFREE(MTYPE_HOST_PREFIX, hle); + } tmp_rmac = hash_release(zl3vni->rmac_table, zrmac); if (tmp_rmac) @@ -3231,8 +3307,8 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, zl3vni_rmac_install(zl3vni, zrmac); } - if (!is_host_present_in_host_list(zrmac->host_list, host_prefix)) - host_list_add_host(zrmac->host_list, host_prefix); + zrmac_find_or_add_host(zrmac, host_prefix); + return 0; } @@ -3241,9 +3317,9 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, struct prefix *host_prefix) { - host_list_delete_host(zrmac->host_list, host_prefix); - if (list_isempty(zrmac->host_list)) { + zrmac_delete_host(zrmac, host_prefix); + if (RB_EMPTY(host_rb_entry_rb, &zrmac->host_rb)) { /* uninstall from kernel */ zl3vni_rmac_uninstall(zl3vni, zrmac); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index b4a8b5d480..c5f6b783aa 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -215,6 +215,15 @@ static inline void zl3vni_get_rmac(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN); } +struct host_rb_entry { + RB_ENTRY(host_rb_entry) hl_entry; + + struct prefix p; +}; + +RB_HEAD(host_rb_entry_rb, host_rb_entry); +RB_PROTOTYPE(host_rb_entry_rb, host_rb_entry, hl_entry, + host_rb_entry_compare); /* * MAC hash table. * @@ -253,7 +262,7 @@ struct zebra_mac_t_ { struct list *neigh_list; /* list of hosts pointing to this remote RMAC */ - struct list *host_list; + struct host_rb_entry_rb host_rb; }; /* From 41db76c235a5d2dda39fad66b57a28800fa53783 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 17 May 2018 08:10:41 -0400 Subject: [PATCH 2/3] zebra: Rename some functions to allow reuse We are going to modify more host_list's to host_rb's so let's rename some functions to take advantage of what is there. Signed-off-by: Donald Sharp --- zebra/zebra_vxlan.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 7cdb790358..30811e4252 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -214,12 +214,12 @@ static int host_rb_entry_compare(const struct host_rb_entry *hle1, RB_GENERATE(host_rb_entry_rb, host_rb_entry, hl_entry, host_rb_entry_compare); -static uint32_t zrmac_host_count(zebra_mac_t *zrmac) +static uint32_t rb_host_count(struct host_rb_entry_rb *hrbe) { struct host_rb_entry *hle; uint32_t count = 0; - RB_FOREACH (hle, host_rb_entry_rb, &zrmac->host_rb) + RB_FOREACH (hle, host_rb_entry_rb, hrbe) count++; return count; @@ -520,7 +520,7 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); vty_out(vty, " Remote VTEP: %s\n", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); - vty_out(vty, " Refcount: %d\n", zrmac_host_count(zrmac)); + vty_out(vty, " Refcount: %d\n", rb_host_count(&zrmac->host_rb)); vty_out(vty, " Prefixes:\n"); RB_FOREACH (hle, host_rb_entry_rb, &zrmac->host_rb) vty_out(vty, " %s\n", @@ -532,7 +532,8 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); json_object_string_add(json, "vtepIp", inet_ntoa(zrmac->fwd_info.r_vtep_ip)); - json_object_int_add(json, "refCount", zrmac_host_count(zrmac)); + json_object_int_add(json, "refCount", + rb_host_count(&zrmac->host_rb)); RB_FOREACH (hle, host_rb_entry_rb, &zrmac->host_rb) json_object_array_add( json_hosts, @@ -3082,7 +3083,8 @@ static void zl3vni_cleanup_all(struct hash_backet *backet, void *args) zebra_vxlan_process_l3vni_oper_down(zl3vni); } -static void zrmac_find_or_add_host(zebra_mac_t *zrmac, struct prefix *host) +static void rb_find_or_add_host(struct host_rb_entry_rb *hrbe, + struct prefix *host) { struct host_rb_entry lookup; struct host_rb_entry *hle; @@ -3090,17 +3092,17 @@ static void zrmac_find_or_add_host(zebra_mac_t *zrmac, struct prefix *host) memset(&lookup, 0, sizeof(lookup)); memcpy(&lookup.p, host, sizeof(*host)); - hle = RB_FIND(host_rb_entry_rb, &zrmac->host_rb, &lookup); + hle = RB_FIND(host_rb_entry_rb, hrbe, &lookup); if (hle) return; hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry)); memcpy(hle, &lookup, sizeof(lookup)); - RB_INSERT(host_rb_entry_rb, &zrmac->host_rb, hle); + RB_INSERT(host_rb_entry_rb, hrbe, hle); } -static void zrmac_delete_host(zebra_mac_t *zrmac, struct prefix *host) +static void rb_delete_host(struct host_rb_entry_rb *hrbe, struct prefix *host) { struct host_rb_entry lookup; struct host_rb_entry *hle; @@ -3108,9 +3110,9 @@ static void zrmac_delete_host(zebra_mac_t *zrmac, struct prefix *host) memset(&lookup, 0, sizeof(lookup)); memcpy(&lookup.p, host, sizeof(*host)); - hle = RB_FIND(host_rb_entry_rb, &zrmac->host_rb, &lookup); + hle = RB_FIND(host_rb_entry_rb, hrbe, &lookup); if (hle) - RB_REMOVE(host_rb_entry_rb, &zrmac->host_rb, hle); + RB_REMOVE(host_rb_entry_rb, hrbe, hle); return; } @@ -3307,7 +3309,7 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, zl3vni_rmac_install(zl3vni, zrmac); } - zrmac_find_or_add_host(zrmac, host_prefix); + rb_find_or_add_host(&zrmac->host_rb, host_prefix); return 0; } @@ -3317,7 +3319,7 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, struct prefix *host_prefix) { - zrmac_delete_host(zrmac, host_prefix); + rb_delete_host(&zrmac->host_rb, host_prefix); if (RB_EMPTY(host_rb_entry_rb, &zrmac->host_rb)) { /* uninstall from kernel */ From f2a503f0cece16dd66e7c258a3bccd967533d074 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 17 May 2018 08:18:23 -0400 Subject: [PATCH 3/3] zebra: The neigh host_list is expensive too The neighbor host_list is expensive as well. Modify the code to take advantage of a rb_tree as well. Signed-off-by: Donald Sharp --- zebra/zebra_vxlan.c | 75 ++++++++++--------------------------- zebra/zebra_vxlan_private.h | 2 +- 2 files changed, 21 insertions(+), 56 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 30811e4252..6b8f915f67 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -476,20 +476,20 @@ static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, { char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - struct listnode *node = NULL; - struct prefix *p = NULL; json_object *json_hosts = NULL; + struct host_rb_entry *hle; if (!json) { vty_out(vty, "Ip: %s\n", ipaddr2str(&n->ip, buf2, sizeof(buf2))); vty_out(vty, " RMAC: %s\n", prefix_mac2str(&n->emac, buf1, sizeof(buf1))); - vty_out(vty, " Refcount: %d\n", listcount(n->host_list)); + vty_out(vty, " Refcount: %d\n", + rb_host_count(&n->host_rb)); vty_out(vty, " Prefixes:\n"); - for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p)) + RB_FOREACH (hle, host_rb_entry_rb, &n->host_rb) vty_out(vty, " %s\n", - prefix2str(p, buf2, sizeof(buf2))); + prefix2str(&hle->p, buf2, sizeof(buf2))); } else { json_hosts = json_object_new_array(); json_object_string_add( @@ -497,11 +497,12 @@ static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, json_object_string_add( json, "routerMac", prefix_mac2str(&n->emac, buf2, sizeof(buf2))); - json_object_int_add(json, "refCount", listcount(n->host_list)); - for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p)) + json_object_int_add(json, "refCount", + rb_host_count(&n->host_rb)); + RB_FOREACH (hle, host_rb_entry_rb, &n->host_rb) json_object_array_add(json_hosts, json_object_new_string(prefix2str( - p, buf2, sizeof(buf2)))); + &hle->p, buf2, sizeof(buf2)))); json_object_object_add(json, "prefixList", json_hosts); } } @@ -3117,44 +3118,6 @@ static void rb_delete_host(struct host_rb_entry_rb *hrbe, struct prefix *host) return; } -static int is_host_present_in_host_list(struct list *list, struct prefix *host) -{ - struct listnode *node = NULL; - struct prefix *p = NULL; - - for (ALL_LIST_ELEMENTS_RO(list, node, p)) { - if (prefix_same(p, host)) - return 1; - } - return 0; -} - -static void host_list_add_host(struct list *list, struct prefix *host) -{ - struct prefix *p = NULL; - - p = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct prefix)); - memcpy(p, host, sizeof(struct prefix)); - - listnode_add_sort(list, p); -} - -static void host_list_delete_host(struct list *list, struct prefix *host) -{ - struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL; - struct prefix *p = NULL; - - for (ALL_LIST_ELEMENTS(list, node, nnode, p)) { - if (prefix_same(p, host)) { - XFREE(MTYPE_HOST_PREFIX, p); - node_to_del = node; - } - } - - if (node_to_del) - list_delete_node(list, node_to_del); -} - /* * Look up MAC hash entry. */ @@ -3374,8 +3337,7 @@ static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip, n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc); assert(n); - n->host_list = list_new(); - n->host_list->cmp = (int (*)(void *, void *))prefix_cmp; + RB_INIT(host_rb_entry_rb, &n->host_rb); memcpy(&n->emac, mac, ETH_ALEN); SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); @@ -3390,10 +3352,14 @@ static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip, static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) { zebra_neigh_t *tmp_n; + struct host_rb_entry *hle; - if (n->host_list) - list_delete_and_null(&n->host_list); - n->host_list = NULL; + while (!RB_EMPTY(host_rb_entry_rb, &n->host_rb)) { + hle = RB_ROOT(host_rb_entry_rb, &n->host_rb); + + RB_REMOVE(host_rb_entry_rb, &n->host_rb, hle); + XFREE(MTYPE_HOST_PREFIX, hle); + } tmp_n = hash_release(zl3vni->nh_table, n); if (tmp_n) @@ -3458,8 +3424,7 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, zl3vni_nh_install(zl3vni, nh); } - if (!is_host_present_in_host_list(nh->host_list, host_prefix)) - host_list_add_host(nh->host_list, host_prefix); + rb_find_or_add_host(&nh->host_rb, host_prefix); return 0; } @@ -3468,9 +3433,9 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, static void zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *nh, struct prefix *host_prefix) { - host_list_delete_host(nh->host_list, host_prefix); - if (list_isempty(nh->host_list)) { + rb_delete_host(&nh->host_rb, host_prefix); + if (RB_EMPTY(host_rb_entry_rb, &nh->host_rb)) { /* uninstall from kernel */ zl3vni_nh_uninstall(zl3vni, nh); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index c5f6b783aa..b2bfcecfc5 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -336,7 +336,7 @@ struct zebra_neigh_t_ { struct in_addr r_vtep_ip; /* list of hosts pointing to this remote NH entry */ - struct list *host_list; + struct host_rb_entry_rb host_rb; }; /*