{
struct bgp_evpn_es *es = es_info->es;
struct bgp_path_info *pi;
- char prefix_buf[PREFIX_STRLEN];
if (!es)
return;
pi = es_info->pi;
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
- zlog_debug(
- "path %s unlinked from es %s",
- prefix2str(&pi->net->p, prefix_buf, sizeof(prefix_buf)),
- es->esi_str);
+ zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni,
+ &pi->net->p, es->esi_str);
list_delete_node(es->macip_path_list, &es_info->es_listnode);
es_info->es = NULL;
struct bgp_path_es_info *es_info;
struct bgp_evpn_es *es;
struct bgp *bgp_evpn = bgp_get_evpn();
- char prefix_buf[PREFIX_STRLEN];
es_info = pi->extra ? pi->extra->es_info : NULL;
/* if the esi is zero just unlink the path from the old es */
bgp_evpn_path_es_unlink(es_info);
if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
- zlog_debug(
- "path %s linked to es %s",
- prefix2str(&pi->net->p, prefix_buf, sizeof(prefix_buf)),
- es->esi_str);
+ zlog_debug("vni %u path %pFX linked to es %s", vni, &pi->net->p,
+ es->esi_str);
/* link mac-ip path to the new destination ES */
es_info->es = es;
listnode_init(&es_info->es_listnode, es_info);
- listnode_add_sort(es->macip_path_list, &es_info->es_listnode);
+ listnode_add(es->macip_path_list, &es_info->es_listnode);
}
static void bgp_evpn_es_path_all_update(struct bgp_evpn_es_vtep *es_vtep,
for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) {
pi = es_info->pi;
+ if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+ continue;
+
if (pi->sub_type != BGP_ROUTE_IMPORTED)
continue;
ip_buf, sizeof(ip_buf)));
json_object_int_add(json, "remoteVniCount",
es->remote_es_evi_cnt);
+ json_object_int_add(json, "vrfCount",
+ listcount(es->es_vrf_list));
+ json_object_int_add(json, "macipPathCount",
+ listcount(es->macip_path_list));
json_object_int_add(json, "inconsistentVniVtepCount",
es->incons_evi_vtep_cnt);
if (listcount(es->es_vtep_list)) {
vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
vty_out(vty, " Remote VNI Count: %d\n",
es->remote_es_evi_cnt);
+ vty_out(vty, " VRF Count: %d\n", listcount(es->es_vrf_list));
+ vty_out(vty, " MACIP Path Count: %d\n",
+ listcount(es->macip_path_list));
vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
es->incons_evi_vtep_cnt);
if (es->inconsistencies) {
*nhg_p = 0;
+ /* L3NHG support is disabled, use legacy-exploded multipath */
+ if (!bgp_mh_info->host_routes_use_l3nhg)
+ return false;
+
parent_pi = get_route_parent_evpn(pi);
if (!parent_pi)
return false;
if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
return false;
- /* L3NHG support is disabled, use legacy-exploded multipath */
- if (!bgp_mh_info->host_routes_use_l3nhg)
- return false;
-
/* non-es path, use legacy-exploded multipath */
esi = bgp_evpn_attr_get_esi(parent_pi->attr);
if (!memcmp(esi, zero_esi, sizeof(*esi)))
return true;
}
+static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
+ struct bgp_evpn_es_vrf *es_vrf,
+ json_object *json)
+{
+ struct bgp_evpn_es *es = es_vrf->es;
+ struct bgp *bgp_vrf = es_vrf->bgp_vrf;
+
+ if (json) {
+ json_object *json_types;
+
+ json_object_string_add(json, "esi", es->esi_str);
+ json_object_string_add(json, "vrf", bgp_vrf->name);
+
+ if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
+ json_types = json_object_new_array();
+ if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+ json_array_string_add(json_types, "active");
+ json_object_object_add(json, "flags", json_types);
+ }
+
+ json_object_int_add(json, "ipv4NHG", es_vrf->nhg_id);
+ json_object_int_add(json, "ipv6NHG", es_vrf->v6_nhg_id);
+ json_object_int_add(json, "refCount", es_vrf->ref_cnt);
+ } else {
+ char flags_str[4];
+
+ flags_str[0] = '\0';
+ if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
+ 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,
+ es_vrf->v6_nhg_id, es_vrf->ref_cnt);
+ }
+}
+
+static void bgp_evpn_es_vrf_show_es(struct vty *vty, json_object *json_array,
+ struct bgp_evpn_es *es)
+{
+ json_object *json = NULL;
+ struct listnode *es_vrf_node;
+ struct bgp_evpn_es_vrf *es_vrf;
+
+ for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf)) {
+ /* create a separate json object for each ES-VRF */
+ if (json_array)
+ json = json_object_new_object();
+ bgp_evpn_es_vrf_show_entry(vty, es_vrf, json);
+ /* add ES-VRF to the json array */
+ if (json_array)
+ json_object_array_add(json_array, json);
+ }
+}
+
+/* Display all ES VRFs */
+void bgp_evpn_es_vrf_show(struct vty *vty, bool uj, struct bgp_evpn_es *es)
+{
+ json_object *json_array = NULL;
+
+ if (uj) {
+ /* create an array of ESs */
+ json_array = json_object_new_array();
+ } else {
+ vty_out(vty, "ES-VRF Flags: A Active\n");
+ vty_out(vty, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
+ "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
+ }
+
+ if (es) {
+ bgp_evpn_es_vrf_show_es(vty, json_array, es);
+ } else {
+ RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree)
+ bgp_evpn_es_vrf_show_es(vty, json_array, es);
+ }
+
+ /* print the array of json-ESs */
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json_array, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json_array);
+ }
+}
+
+/* Display specific ES VRF */
+void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj)
+{
+ struct bgp_evpn_es *es;
+
+ es = bgp_evpn_es_find(esi);
+ if (es) {
+ bgp_evpn_es_vrf_show(vty, uj, es);
+ } else {
+ if (!uj)
+ vty_out(vty, "ESI not found\n");
+ }
+}
+
/*****************************************************************************/
/* Ethernet Segment to EVI association -
* 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
}
}
+/* Display all MAC-IP VNI routes linked to an ES */
+static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
+ json_object *json, int detail)
+{
+ struct bgp_node *rn;
+ struct bgp_path_info *pi;
+ int header = detail ? 0 : 1;
+ uint32_t path_cnt;
+ struct listnode *node;
+ struct bgp_evpn_es *es;
+ struct bgp_path_es_info *es_info;
+ struct bgp *bgp = bgp_get_evpn();
+ json_object *json_paths = NULL;
+
+ if (!bgp)
+ return;
+
+ path_cnt = 0;
+
+ if (json)
+ json_paths = json_object_new_array();
+
+ RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
+
+ if (esi && memcmp(esi, &es->esi, sizeof(*esi)))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) {
+ json_object *json_path = NULL;
+
+ pi = es_info->pi;
+ rn = pi->net;
+
+ if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+ continue;
+
+ /* Overall header/legend displayed once. */
+ if (header) {
+ bgp_evpn_show_route_header(vty, bgp, 0, json);
+ header = 0;
+ }
+
+ path_cnt++;
+
+ if (json)
+ json_path = json_object_new_array();
+
+ if (detail)
+ route_vty_out_detail(vty, bgp, rn, pi,
+ AFI_L2VPN, SAFI_EVPN,
+ json_path);
+ else
+ route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
+ json_path, false);
+
+ if (json)
+ json_object_array_add(json_paths, json_path);
+ }
+ }
+
+ if (json) {
+ json_object_object_add(json, "paths", json_paths);
+ json_object_int_add(json, "numPaths", path_cnt);
+ } else {
+ if (path_cnt == 0)
+ vty_out(vty, "There are no MAC-IP ES paths");
+ else
+ vty_out(vty, "\nDisplayed %u paths\n", path_cnt);
+ vty_out(vty, "\n");
+ }
+}
+
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
struct vty *vty, struct in_addr vtep_ip,
json_object *json, int detail)
return CMD_SUCCESS;
}
+DEFPY(show_bgp_l2vpn_evpn_es_vrf, show_bgp_l2vpn_evpn_es_vrf_cmd,
+ "show bgp l2vpn evpn es-vrf [NAME$esi_str] [json$uj]",
+ SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR
+ "Ethernet Segment\n"
+ "ES ID\n" JSON_STR)
+{
+ esi_t esi;
+
+ if (esi_str) {
+ if (!str_to_esi(esi_str, &esi)) {
+ vty_out(vty, "%%Malformed ESI\n");
+ return CMD_WARNING;
+ }
+ bgp_evpn_es_vrf_show_esi(vty, &esi, uj);
+ } else {
+
+ bgp_evpn_es_vrf_show(vty, uj, NULL);
+ }
+
+ return CMD_SUCCESS;
+}
+
/*
* Display EVPN neighbor summary.
*/
return CMD_SUCCESS;
}
+DEFPY_HIDDEN(
+ show_bgp_l2vpn_evpn_route_mac_ip_es,
+ show_bgp_l2vpn_evpn_route_mac_ip_es_cmd,
+ "show bgp l2vpn evpn route mac-ip-es [NAME$esi_str|detail$detail] [json$uj]",
+ SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR
+ "EVPN route information\n"
+ "MAC IP routes linked to the ES\n"
+ "ES ID\n"
+ "Detailed information\n" JSON_STR)
+{
+ esi_t esi;
+ esi_t *esi_p;
+ json_object *json = NULL;
+
+ if (esi_str) {
+ if (!str_to_esi(esi_str, &esi)) {
+ vty_out(vty, "%%Malformed ESI\n");
+ return CMD_WARNING;
+ }
+ esi_p = &esi;
+ } else {
+ esi_p = NULL;
+ }
+
+ if (uj)
+ json = json_object_new_object();
+ bgp_evpn_show_routes_mac_ip_es(vty, esi_p, json, !!detail);
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
/*
* Display EVPN import route-target hash table
*/
/* "show bgp l2vpn evpn" commands. */
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_evi_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_vrf_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
+ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_mac_ip_es_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
vty_out(vty, "\n");
if (safi == SAFI_EVPN) {
+ struct bgp_path_es_info *path_es_info = NULL;
+
+ if (path->extra)
+ path_es_info = path->extra->es_info;
+
if (bgp_evpn_is_esi_valid(&attr->esi)) {
+ /* XXX - add these params to the json out */
vty_out(vty, "%*s", 20, " ");
- vty_out(vty, "ESI:%s\n",
- esi_to_str(&attr->esi,
- esi_buf, sizeof(esi_buf)));
+ vty_out(vty, "ESI:%s",
+ esi_to_str(&attr->esi, esi_buf,
+ sizeof(esi_buf)));
+ if (path_es_info && path_es_info->es)
+ vty_out(vty, " VNI: %u",
+ path_es_info->vni);
+ vty_out(vty, "\n");
}
if (attr->flag &
ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) {
}
static void route_vty_out_detail_es_info(struct vty *vty,
- struct attr *attr, json_object *json_path)
+ struct bgp_path_info *pi,
+ struct attr *attr,
+ json_object *json_path)
{
char esi_buf[ESI_STR_LEN];
bool es_local = !!CHECK_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL);
ATTR_ES_PEER_ACTIVE);
bool peer_proxy = !!CHECK_FLAG(attr->es_flags,
ATTR_ES_PEER_PROXY);
-
esi_to_str(&attr->esi, esi_buf, sizeof(esi_buf));
if (json_path) {
json_object *json_es_info = NULL;
if (safi == SAFI_EVPN &&
bgp_evpn_is_esi_valid(&attr->esi)) {
- route_vty_out_detail_es_info(vty, attr, json_path);
+ route_vty_out_detail_es_info(vty, path, attr, json_path);
}
/* Line 3 display Origin, Med, Locpref, Weight, Tag, valid,