+// SPDX-License-Identifier: GPL-2.0-or-later
/* EVPN Multihoming procedures
*
* Copyright (C) 2019 Cumulus Networks, Inc.
* Anuradha Karuppiah
*
- * This file is part of FRR.
- *
- * FRRouting 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, or (at your option) any
- * later version.
- *
- * FRRouting 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.
- *
*/
#include <zebra.h>
struct prefix_rd *prd;
if (vpn) {
- rt_table = vpn->route_table;
+ rt_table = vpn->ip_table;
prd = &vpn->prd;
} else {
rt_table = es->route_table;
/* Next, locate route node in the global EVPN routing table.
* Note that this table is a 2-level tree (RD-level + Prefix-level)
*/
- global_dest =
- bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)p, prd);
+ global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi,
+ safi, p, prd, NULL);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
if (route_changed) {
struct bgp_path_info *global_pi;
- dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
- p, &es->es_base_frag->prd);
+ dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ p, &es->es_base_frag->prd,
+ NULL);
bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest,
attr_new, &global_pi, &route_changed);
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id)
{
- int ret;
esi_t esi;
uint8_t ipaddr_len;
struct in_addr vtep_ip;
build_evpn_type4_prefix(&p, &esi, vtep_ip);
/* Process the route. */
if (attr) {
- ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
- afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- &prd, NULL, 0, 0, NULL);
+ bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
+ safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL,
+ 0, 0, NULL);
} else {
- ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
- afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- &prd, NULL, 0, NULL);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
+ NULL);
}
- return ret;
+ return 0;
}
/* Check if a prefix belongs to the local ES */
bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
/* First, create (or fetch) route node within the VNI. */
- dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
+ dest = bgp_node_get(vpn->ip_table, (struct prefix *)p);
/* Create or update route entry. */
ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
if (route_changed) {
struct bgp_path_info *global_pi;
- dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
- p, global_rd);
+ dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ p, global_rd, NULL);
bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
attr_new, &global_pi, &route_changed);
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id)
{
- int ret;
struct prefix_rd prd;
esi_t esi;
uint32_t eth_tag;
build_evpn_type1_prefix(&p, eth_tag, &esi, vtep_ip);
/* Process the route. */
if (attr) {
- ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
- afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- &prd, NULL, 0, 0, NULL);
+ bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi,
+ safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL,
+ 0, 0, NULL);
} else {
- ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
- afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- &prd, NULL, 0, NULL);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
+ NULL);
}
- return ret;
+ return 0;
}
void bgp_evpn_mh_config_ead_export_rt(struct bgp *bgp,
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("update paths linked to es %s on es-vrf %s %s",
- es->esi_str, es_vrf->bgp_vrf->name, reason);
+ es->esi_str, es_vrf->bgp_vrf->name_pretty, reason);
for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) {
pi = es_info->pi;
struct bgp_evpn_es *es)
{
json_object *json_frag;
- char buf1[RD_ADDRSTRLEN];
struct listnode *node;
struct bgp_evpn_es_frag *es_frag;
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
json_frag = json_object_new_object();
- json_object_string_add(
- json_frag, "rd",
- prefix_rd2str(&es_frag->prd, buf1, sizeof(buf1)));
+ json_object_string_addf(json_frag, "rd", "%pRDP",
+ &es_frag->prd);
json_object_int_add(json_frag, "eviCount",
listcount(es_frag->es_evi_frag_list));
struct bgp_evpn_es *es)
{
struct listnode *node;
- char buf1[RD_ADDRSTRLEN];
struct bgp_evpn_es_frag *es_frag;
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
- vty_out(vty, " %s EVIs: %d\n",
- prefix_rd2str(&es_frag->prd, buf1, sizeof(buf1)),
+ vty_out(vty, " %pRDP EVIs: %d\n", &es_frag->prd,
listcount(es_frag->es_evi_frag_list));
}
}
struct listnode *node;
struct bgp_evpn_es_vtep *es_vtep;
bool first = true;
- char ip_buf[INET6_ADDRSTRLEN];
+ char ip_buf[INET_ADDRSTRLEN];
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
static void bgp_evpn_es_show_entry(struct vty *vty,
struct bgp_evpn_es *es, json_object *json)
{
- char buf1[RD_ADDRSTRLEN];
struct listnode *node;
struct bgp_evpn_es_vtep *es_vtep;
json_object_string_add(json, "esi", es->esi_str);
if (es->es_base_frag)
- json_object_string_add(
- json, "rd",
- prefix_rd2str(&es->es_base_frag->prd, buf1,
- sizeof(buf1)));
+ json_object_string_addf(json, "rd", "%pRDP",
+ &es->es_base_frag->prd);
if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
json_types = json_object_new_array();
bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
- if (es->es_base_frag)
- prefix_rd2str(&es->es_base_frag->prd, buf1,
- sizeof(buf1));
- else
- strlcpy(buf1, "-", sizeof(buf1));
-
- vty_out(vty, "%-30s %-5s %-21s %-8d %s\n",
- es->esi_str, type_str, buf1,
- listcount(es->es_evi_list), vtep_str);
+ vty_out(vty, "%-30s %-5s %-21pRDP %-8d %s\n", es->esi_str,
+ type_str, &es->es_base_frag->prd,
+ listcount(es->es_evi_list), vtep_str);
}
}
} else {
char incons_str[BGP_EVPNES_INCONS_STR_SZ];
char type_str[4];
- char buf1[RD_ADDRSTRLEN];
type_str[0] = '\0';
if (es->flags & BGP_EVPNES_LOCAL)
if (es->flags & BGP_EVPNES_REMOTE)
strlcat(type_str, "R", sizeof(type_str));
- if (es->es_base_frag)
- prefix_rd2str(&es->es_base_frag->prd, buf1,
- sizeof(buf1));
- else
- strlcpy(buf1, "-", sizeof(buf1));
-
vty_out(vty, "ESI: %s\n", es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
- vty_out(vty, " RD: %s\n", buf1);
+ vty_out(vty, " RD: %pRDP\n", &es->es_base_frag->prd);
vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
if (es->flags & BGP_EVPNES_LOCAL)
vty_out(vty, " Local ES DF preference: %u\n",
if (!memcmp(esi, zero_esi, sizeof(*esi)))
return false;
+ /* we don't support NHG for d-vni yet */
+ if (bgp_evpn_mpath_has_dvni(bgp_vrf, pi))
+ return false;
+
bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &use_l3nhg, &is_l3nhg_active,
&es_vrf);
json_object *json_types;
json_object_string_add(json, "esi", es->esi_str);
- json_object_string_add(json, "vrf", bgp_vrf->name);
+ json_object_string_add(json, "vrf", bgp_vrf->name_pretty);
if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
json_types = json_object_new_array();
strlcat(flags_str, "A", sizeof(flags_str));
vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str,
- bgp_vrf->name, flags_str, es_vrf->nhg_id,
+ bgp_vrf->name_pretty, flags_str, es_vrf->nhg_id,
es_vrf->v6_nhg_id, es_vrf->ref_cnt);
}
}
struct listnode *node;
struct bgp_evpn_es_evi_vtep *evi_vtep;
bool first = true;
- char ip_buf[INET6_ADDRSTRLEN];
+ char ip_buf[INET_ADDRSTRLEN];
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
json_object *json_types;
json_object_string_add(json, "esi", es_evi->es->esi_str);
- json_object_int_add(json, "vni", es_evi->vpn->vni);
+ if (es_evi->vpn)
+ json_object_int_add(json, "vni", es_evi->vpn->vni);
if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
BGP_EVPNES_EVI_REMOTE)) {
static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
struct bgp_evpn_es_evi *es_evi, json_object *json)
{
- char buf1[RD_ADDRSTRLEN];
+ enum asnotation_mode mode;
+
+ mode = bgp_get_asnotation(es_evi->vpn->bgp_vrf);
if (json) {
json_object *json_flags;
/* Add the "brief" info first */
bgp_evpn_es_evi_show_entry(vty, es_evi, json);
if (es_evi->es_frag)
- json_object_string_add(
- json, "esFragmentRd",
- prefix_rd2str(&es_evi->es_frag->prd, buf1,
- sizeof(buf1)));
+ json_object_string_addf(json, "esFragmentRd",
+ BGP_RD_AS_FORMAT(mode),
+ &es_evi->es_frag->prd);
if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
json_flags = json_object_new_array();
json_array_string_add(json_flags, "es-vtep-mismatch");
vty_out(vty, "VNI: %d ESI: %s\n",
es_evi->vpn->vni, es_evi->es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
- if (es_evi->es_frag)
- vty_out(vty, " ES fragment RD: %s\n",
- prefix_rd2str(&es_evi->es_frag->prd, buf1,
- sizeof(buf1)));
+ if (es_evi->es_frag) {
+ vty_out(vty, " ES fragment RD: ");
+ vty_out(vty, BGP_RD_AS_FORMAT(mode),
+ &es_evi->es_frag->prd);
+ vty_out(vty, "\n");
+ }
vty_out(vty, " Inconsistencies: %s\n",
(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
"es-vtep-mismatch":"-");
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) {
if (add)
zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
- nh->bgp_vrf->name, nh->nh_str, &nh->rmac);
+ nh->bgp_vrf->name_pretty, nh->nh_str,
+ &nh->rmac);
else if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("evpn vrf %s nh %s del to zebra",
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
}
frrtrace(2, frr_bgp, evpn_mh_nh_rmac_zsend, add, nh);
}
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s rmac %pEA add", n->bgp_vrf->name,
- n->nh_str, &n->rmac);
+ zlog_debug("evpn vrf %s nh %s rmac %pEA add",
+ n->bgp_vrf->name_pretty, n->nh_str, &n->rmac);
bgp_evpn_nh_zebra_update(n, true);
return n;
}
return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf->name,
- n->nh_str);
+ zlog_debug("evpn vrf %s nh %s del to zebra",
+ bgp_vrf->name_pretty, n->nh_str);
bgp_evpn_nh_zebra_update(n, false);
list_delete(&n->pi_list);
void bgp_evpn_nh_init(struct bgp *bgp_vrf)
{
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh init", bgp_vrf->name);
+ zlog_debug("evpn vrf %s nh init", bgp_vrf->name_pretty);
bgp_vrf->evpn_nh_table = hash_create(
bgp_evpn_nh_hash_keymake, bgp_evpn_nh_cmp, "BGP EVPN NH table");
}
struct bgp_path_evpn_nh_info *nh_info;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s flush", nh->bgp_vrf->name,
+ zlog_debug("evpn vrf %s nh %s flush", nh->bgp_vrf->name_pretty,
nh->nh_str);
/* force flush paths */
void bgp_evpn_nh_finish(struct bgp *bgp_vrf)
{
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh finish", bgp_vrf->name);
+ zlog_debug("evpn vrf %s nh finish", bgp_vrf->name_pretty);
hash_iterate(
bgp_vrf->evpn_nh_table,
(void (*)(struct hash_bucket *, void *))bgp_evpn_nh_flush_cb,
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("evpn vrf %s nh %s ref_pi update",
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
nh->ref_pi = pi;
/* If we have a new pi copy rmac from it and update
* zebra if the new rmac is different
return;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
- zlog_debug("evpn vrf %s nh %s ref_pi clear", nh->bgp_vrf->name,
- nh->nh_str);
+ zlog_debug("evpn vrf %s nh %s ref_pi clear",
+ nh->bgp_vrf->name_pretty, nh->nh_str);
nh->ref_pi = NULL;
/* try to find another ref_pi */
bgp_evpn_nh_update_ref_pi(nh);
pi->net ? prefix2str(&pi->net->p, prefix_buf,
sizeof(prefix_buf))
: "",
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
list_delete_node(nh->pi_list, &nh_info->nh_listnode);
if (!bgp_vrf->evpn_nh_table) {
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("path %pFX linked to vrf %s failed",
- &pi->net->p, bgp_vrf->name);
+ &pi->net->p, bgp_vrf->name_pretty);
return;
}
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
zlog_debug("path %pFX linked to nh %s %s", &pi->net->p,
- nh->bgp_vrf->name, nh->nh_str);
+ nh->bgp_vrf->name_pretty, nh->nh_str);
/* link mac-ip path to the new nh */
nh_info->nh = nh;
if (!nh->ref_pi)
zlog_debug(
"path %pFX linked to nh %s %s with no valid pi",
- &pi->net->p, nh->bgp_vrf->name, nh->nh_str);
+ &pi->net->p, nh->bgp_vrf->name_pretty,
+ nh->nh_str);
}
}
else
prefix_buf[0] = '\0';
if (json) {
- json_object_string_add(json, "vrf", nh->bgp_vrf->name);
+ json_object_string_add(json, "vrf", nh->bgp_vrf->name_pretty);
json_object_string_add(json, "ip", nh->nh_str);
json_object_string_add(json, "rmac", mac_buf);
json_object_string_add(json, "basePath", prefix_buf);
json_object_int_add(json, "pathCount", listcount(nh->pi_list));
} else {
- vty_out(vty, "%-15s %-15s %-17s %-10d %s\n", nh->bgp_vrf->name,
- nh->nh_str, mac_buf, listcount(nh->pi_list),
- prefix_buf);
+ vty_out(vty, "%-15s %-15s %-17s %-10d %s\n",
+ nh->bgp_vrf->name_pretty, nh->nh_str, mac_buf,
+ listcount(nh->pi_list), prefix_buf);
}
/* add ES to the json array */