]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: commands to display L3 NHGs and MAC-IP paths linked to an ES
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sat, 9 May 2020 02:49:33 +0000 (19:49 -0700)
committerAnuradha Karuppiah <anuradhak@nvidia.com>
Tue, 24 Nov 2020 19:06:08 +0000 (11:06 -0800)
Sample output -
===============
torm-11# sh bgp l2vpn evpn es-vrf
ES-VRF Flags: A Active
ESI                            VRF             Flags IPv4-NHG IPv6-NHG Ref
03:44:38:39:ff:ff:01:00:00:01  vrf3            A     1        0        2
03:44:38:39:ff:ff:01:00:00:01  vrf2            A     6        0        4
03:44:38:39:ff:ff:01:00:00:01  vrf1            A     7        0        4
03:44:38:39:ff:ff:01:00:00:02  vrf3            A     2        0        2
03:44:38:39:ff:ff:01:00:00:02  vrf2            A     4        0        4
03:44:38:39:ff:ff:01:00:00:02  vrf1            A     8        0        4

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
bgpd/bgp_evpn_mh.c
bgpd/bgp_evpn_mh.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_route.c

index 6a8799d4cd2b14ac972b0225c183f1ab419c6f0a..f559fc7f4a91e274b5ea366122b24ca1e071de48 100644 (file)
@@ -1381,17 +1381,14 @@ void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info)
 {
        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;
@@ -1411,7 +1408,6 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
        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 */
@@ -1441,15 +1437,13 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
        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,
@@ -1467,6 +1461,9 @@ 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;
 
@@ -2003,6 +2000,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
                                                 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)) {
@@ -2047,6 +2048,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
                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) {
@@ -2411,6 +2415,10 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
 
        *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;
@@ -2423,10 +2431,6 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
        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)))
@@ -2463,6 +2467,104 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
        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
index f7aaf157c699aad9dd95ccc90dc0c2f7f6a50923..bde46e272bbac7b79407041172f0d712de7aa2a5 100644 (file)
@@ -358,5 +358,8 @@ extern void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni,
 extern bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh);
 extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf,
                                     struct bgp_path_info *pi, uint32_t *nhg_p);
+extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
+                                struct bgp_evpn_es *es);
+extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj);
 
 #endif /* _FRR_BGP_EVPN_MH_H */
index e9e2aafebbec174a26973ef40e55f6306b58e2f5..e5e91deb252c46e86c9a841d14c4e0100449584d 100644 (file)
@@ -686,6 +686,78 @@ static void show_esi_routes(struct bgp *bgp,
        }
 }
 
+/* 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)
@@ -3967,6 +4039,28 @@ DEFPY(show_bgp_l2vpn_evpn_es,
        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.
  */
@@ -4517,6 +4611,43 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
        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
  */
@@ -5754,6 +5885,7 @@ void bgp_ethernetvpn_init(void)
        /* "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);
@@ -5765,6 +5897,7 @@ void bgp_ethernetvpn_init(void)
                        &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);
 
index 29dbdbad897944406c89c3e0ba0d598b184c8289..db3eb95353d9b80586d7a1c0daad9f6875cddad0 100644 (file)
@@ -8620,11 +8620,21 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
                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)) {
@@ -9301,7 +9311,9 @@ static const char *bgp_path_selection_reason2str(
 }
 
 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);
@@ -9311,7 +9323,6 @@ static void route_vty_out_detail_es_info(struct vty *vty,
                        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;
@@ -9846,7 +9857,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
 
        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,