diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index ba612f7696..0febcbbf69 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -18,6 +18,7 @@ struct host_rb_entry { RB_ENTRY(host_rb_entry) hl_entry; struct prefix p; + uint32_t pathcnt; }; RB_HEAD(host_rb_tree_entry, host_rb_entry); diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 75e7e20176..bc477266d3 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -3795,7 +3795,7 @@ void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS) memset(&dummy_prefix, 0, sizeof(dummy_prefix)); dummy_prefix.family = AF_EVPN; dummy_prefix.prefixlen = (sizeof(struct evpn_addr) * 8); - dummy_prefix.prefix.route_type = 1; /* XXX - fixup to type-1 def */ + dummy_prefix.prefix.route_type = BGP_EVPN_AD_ROUTE; /* XXX - fixup to type-1 def */ dummy_prefix.prefix.ead_addr.ip.ipa_type = nh.ipa_type; if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0c4f7e02f8..f75407606e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2863,6 +2863,28 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) if (same) { if (dest && same == dest->selected_fib) SET_FLAG(same->status, ROUTE_ENTRY_ROUTE_REPLACING); + + struct nexthop *tmp_nh; + + /* Free up the evpn nhs of the re to be replaced.*/ + for (ALL_NEXTHOPS(same->nhe->nhg, tmp_nh)) { + struct ipaddr vtep_ip; + + if (CHECK_FLAG(tmp_nh->flags, NEXTHOP_FLAG_EVPN)) { + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + if (ere->afi == AFI_IP) { + vtep_ip.ipa_type = IPADDR_V4; + memcpy(&(vtep_ip.ipaddr_v4), &(tmp_nh->gate.ipv4), + sizeof(struct in_addr)); + } else { + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&(vtep_ip.ipaddr_v6), &(tmp_nh->gate.ipv6), + sizeof(struct in6_addr)); + } + zebra_rib_queue_evpn_route_del(same->vrf_id, &vtep_ip, &ere->p); + } + } + rib_delnode(rn, same); } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 04585f6312..6a0cee6ced 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -355,6 +355,7 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty, char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; json_object *json_hosts = NULL; + json_object *json_prefix = NULL; struct host_rb_entry *hle; if (!json) { @@ -370,7 +371,7 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty, rb_host_count(&n->host_rb)); vty_out(vty, " Prefixes:\n"); RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) - vty_out(vty, " %pFX\n", &hle->p); + vty_out(vty, " %pFX (paths: %d)\n", &hle->p, hle->pathcnt); } } else { json_hosts = json_object_new_array(); @@ -385,11 +386,13 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty, else { json_object_int_add(json, "refCount", rb_host_count(&n->host_rb)); - RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) - json_object_array_add( - json_hosts, - json_object_new_string(prefix2str( - &hle->p, buf2, sizeof(buf2)))); + RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) { + json_prefix = json_object_new_object(); + json_object_string_add(json_prefix, "prefix", + prefix2str(&hle->p, buf2, sizeof(buf2))); + json_object_int_add(json_prefix, "pathCount", hle->pathcnt); + json_object_array_add(json_hosts, json_prefix); + } json_object_object_add(json, "prefixList", json_hosts); } } @@ -1143,11 +1146,23 @@ static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe, memcpy(&lookup.p, host, sizeof(*host)); hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup); - if (hle) + if (hle) { + /* never pathcount evpn A-D / MH routes because zebra is not aware + * of specific paths. ADD operations are considered to be upsert + * leading to path count increasing without ever decreasing. A single + * DEL operation should fully remove the prefix from the next-hop. + */ + if (host->family == AF_EVPN && + ((const struct prefix_evpn *)host)->prefix.route_type == BGP_EVPN_AD_ROUTE) + return; + + hle->pathcnt++; return; + } hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry)); memcpy(hle, &lookup, sizeof(lookup)); + hle->pathcnt = 1; RB_INSERT(host_rb_tree_entry, hrbe, hle); } @@ -1162,8 +1177,11 @@ static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host) hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup); if (hle) { - RB_REMOVE(host_rb_tree_entry, hrbe, hle); - XFREE(MTYPE_HOST_PREFIX, hle); + hle->pathcnt--; + if (hle->pathcnt == 0) { + RB_REMOVE(host_rb_tree_entry, hrbe, hle); + XFREE(MTYPE_HOST_PREFIX, hle); + } } return;