mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
zebra: Add refcounts to evpn nexthop prefixes
With bgpd no longer sending withdraws for EVPN prefix routes zebra needs to track the path/ref count of prefixes for an EVPN nexthop. When a route is updated the count is first increased with the new paths and then decreased with the paths of the existing/"same" route entry. However the same evpn route methods are used for EVPN MH as well, where bgpd already tracks the references. It is expected that an ADD operation for the respective A-D routes is handled as an upsert, a DEL operation should really remove the respective A-D reference on a next-hop. For this the old behaviour (no path/ref counting in zebra) is preserved. Signed-off-by: Christopher Dziomba <christopher.dziomba@telekom.de>
This commit is contained in:
parent
068a00f11e
commit
069a23da10
|
@ -18,6 +18,7 @@ struct host_rb_entry {
|
||||||
RB_ENTRY(host_rb_entry) hl_entry;
|
RB_ENTRY(host_rb_entry) hl_entry;
|
||||||
|
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
|
uint32_t pathcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
RB_HEAD(host_rb_tree_entry, host_rb_entry);
|
RB_HEAD(host_rb_tree_entry, host_rb_entry);
|
||||||
|
|
|
@ -3795,7 +3795,7 @@ void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS)
|
||||||
memset(&dummy_prefix, 0, sizeof(dummy_prefix));
|
memset(&dummy_prefix, 0, sizeof(dummy_prefix));
|
||||||
dummy_prefix.family = AF_EVPN;
|
dummy_prefix.family = AF_EVPN;
|
||||||
dummy_prefix.prefixlen = (sizeof(struct evpn_addr) * 8);
|
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;
|
dummy_prefix.prefix.ead_addr.ip.ipa_type = nh.ipa_type;
|
||||||
|
|
||||||
if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD) {
|
if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD) {
|
||||||
|
|
|
@ -2863,6 +2863,28 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
|
||||||
if (same) {
|
if (same) {
|
||||||
if (dest && same == dest->selected_fib)
|
if (dest && same == dest->selected_fib)
|
||||||
SET_FLAG(same->status, ROUTE_ENTRY_ROUTE_REPLACING);
|
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);
|
rib_delnode(rn, same);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -355,6 +355,7 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
|
||||||
char buf1[ETHER_ADDR_STRLEN];
|
char buf1[ETHER_ADDR_STRLEN];
|
||||||
char buf2[INET6_ADDRSTRLEN];
|
char buf2[INET6_ADDRSTRLEN];
|
||||||
json_object *json_hosts = NULL;
|
json_object *json_hosts = NULL;
|
||||||
|
json_object *json_prefix = NULL;
|
||||||
struct host_rb_entry *hle;
|
struct host_rb_entry *hle;
|
||||||
|
|
||||||
if (!json) {
|
if (!json) {
|
||||||
|
@ -370,7 +371,7 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
|
||||||
rb_host_count(&n->host_rb));
|
rb_host_count(&n->host_rb));
|
||||||
vty_out(vty, " Prefixes:\n");
|
vty_out(vty, " Prefixes:\n");
|
||||||
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
|
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 {
|
} else {
|
||||||
json_hosts = json_object_new_array();
|
json_hosts = json_object_new_array();
|
||||||
|
@ -385,11 +386,13 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
|
||||||
else {
|
else {
|
||||||
json_object_int_add(json, "refCount",
|
json_object_int_add(json, "refCount",
|
||||||
rb_host_count(&n->host_rb));
|
rb_host_count(&n->host_rb));
|
||||||
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
|
RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) {
|
||||||
json_object_array_add(
|
json_prefix = json_object_new_object();
|
||||||
json_hosts,
|
json_object_string_add(json_prefix, "prefix",
|
||||||
json_object_new_string(prefix2str(
|
prefix2str(&hle->p, buf2, sizeof(buf2)));
|
||||||
&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);
|
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));
|
memcpy(&lookup.p, host, sizeof(*host));
|
||||||
|
|
||||||
hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry));
|
hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry));
|
||||||
memcpy(hle, &lookup, sizeof(lookup));
|
memcpy(hle, &lookup, sizeof(lookup));
|
||||||
|
hle->pathcnt = 1;
|
||||||
|
|
||||||
RB_INSERT(host_rb_tree_entry, hrbe, hle);
|
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);
|
hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
|
||||||
if (hle) {
|
if (hle) {
|
||||||
RB_REMOVE(host_rb_tree_entry, hrbe, hle);
|
hle->pathcnt--;
|
||||||
XFREE(MTYPE_HOST_PREFIX, hle);
|
if (hle->pathcnt == 0) {
|
||||||
|
RB_REMOVE(host_rb_tree_entry, hrbe, hle);
|
||||||
|
XFREE(MTYPE_HOST_PREFIX, hle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue