From: Anuradha Karuppiah Date: Sun, 17 May 2020 17:59:30 +0000 (-0700) Subject: zebra: add json output for zebra ES, ES-EVI and access vlan dumps X-Git-Tag: base_7.6~347^2~3 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=acffa256ba4f0726215db36f8ef553361f1ada8b;p=matthieu%2Ffrr.git zebra: add json output for zebra ES, ES-EVI and access vlan dumps 1. ES root@torm-11:mgmt:~# vtysh -c "show evpn es 03:44:38:39:ff:ff:01:00:00:01 json" |python -m json.tool { "accessPort": "hostbond1", "dfPreference": 50000, "esi": "03:44:38:39:ff:ff:01:00:00:01", "flags": [ "local", "remote", "readyForBgp", "bridgePort", "operUp", "nexthopGroupActive" ], "macCount": 10, "nexthopGroup": 536870913, "vniCount": 10, "vteps": [ { "dfAlgorithm": "preference", "dfPreference": 32767, "nexthopId": 268435460, "vtep": "27.0.0.16" }, { "dfAlgorithm": "preference", "dfPreference": 32767, "nexthopId": 268435463, "vtep": "27.0.0.17" } ] } >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. ES-EVI - root@torm-11:mgmt:~# vtysh -c "show evpn es-evi vni 1001 detail json" |python -m json.tool [ { "esi": "03:44:38:39:ff:ff:01:00:00:01", "flags": [ "local", "readyForBgp" ], "vni": 1001 }, { "esi": "03:44:38:39:ff:ff:01:00:00:02", "flags": [ "local", "readyForBgp" ], "vni": 1001 }, ] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. access-vlan root@torm-11:mgmt:~# vtysh -c "show evpn access-vlan 1001 json" |python -m json. tool { "memberIfCount": 4, "members": [ { "ifName": "hostbond4" }, { "ifName": "hostbond1" }, { "ifName": "hostbond2" }, { "ifName": "hostbond3" } ], "vlan": 1001, "vni": 1001, "vxlanIf": "vx-1001" } root@torm-11:mgmt:~# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Signed-off-by: Anuradha Karuppiah --- diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 02c0736767..6b00150f7a 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -255,12 +255,29 @@ static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es, } static void zebra_evpn_es_evi_show_entry(struct vty *vty, - struct zebra_evpn_es_evi *es_evi, json_object *json) + struct zebra_evpn_es_evi *es_evi, + json_object *json_array) { char type_str[4]; - if (json) { - /* XXX */ + if (json_array) { + json_object *json; + json_object *json_types; + + /* Separate JSON object for each es-evi entry */ + json = json_object_new_object(); + + json_object_string_add(json, "esi", es_evi->es->esi_str); + json_object_int_add(json, "vni", es_evi->zevpn->vni); + if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) { + json_types = json_object_new_array(); + if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) + json_array_string_add(json_types, "local"); + json_object_object_add(json, "type", json_types); + } + + /* Add es-evi entry to json array */ + json_object_array_add(json_array, json); } else { type_str[0] = '\0'; if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) @@ -272,13 +289,36 @@ static void zebra_evpn_es_evi_show_entry(struct vty *vty, } } -static void zebra_evpn_es_evi_show_entry_detail(struct vty *vty, - struct zebra_evpn_es_evi *es_evi, json_object *json) +static void +zebra_evpn_es_evi_show_entry_detail(struct vty *vty, + struct zebra_evpn_es_evi *es_evi, + json_object *json_array) { char type_str[4]; - if (json) { - /* XXX */ + if (json_array) { + json_object *json; + json_object *json_flags; + + /* Separate JSON object for each es-evi entry */ + json = json_object_new_object(); + + json_object_string_add(json, "esi", es_evi->es->esi_str); + json_object_int_add(json, "vni", es_evi->zevpn->vni); + if (es_evi->flags + & (ZEBRA_EVPNES_EVI_LOCAL + | ZEBRA_EVPNES_EVI_READY_FOR_BGP)) { + json_flags = json_object_new_array(); + if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) + json_array_string_add(json_flags, "local"); + if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP) + json_array_string_add(json_flags, + "readyForBgp"); + json_object_object_add(json, "flags", json_flags); + } + + /* Add es-evi entry to json array */ + json_object_array_add(json_array, json); } else { type_str[0] = '\0'; if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) @@ -296,15 +336,17 @@ static void zebra_evpn_es_evi_show_entry_detail(struct vty *vty, } static void zebra_evpn_es_evi_show_one_evpn(zebra_evpn_t *zevpn, - struct vty *vty, json_object *json, int detail) + struct vty *vty, + json_object *json_array, int detail) { struct zebra_evpn_es_evi *es_evi; RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree) { if (detail) - zebra_evpn_es_evi_show_entry_detail(vty, es_evi, json); + zebra_evpn_es_evi_show_entry_detail(vty, es_evi, + json_array); else - zebra_evpn_es_evi_show_entry(vty, es_evi, json); + zebra_evpn_es_evi_show_entry(vty, es_evi, json_array); } } @@ -326,34 +368,46 @@ static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket *bucket, void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail) { - json_object *json = NULL; + json_object *json_array = NULL; struct zebra_vrf *zvrf; struct evpn_mh_show_ctx wctx; zvrf = zebra_vrf_get_evpn(); + if (uj) + json_array = json_object_new_array(); memset(&wctx, 0, sizeof(wctx)); wctx.vty = vty; - wctx.json = json; + wctx.json = json_array; wctx.detail = detail; - if (!detail && !json) { + if (!detail && !json_array) { vty_out(vty, "Type: L local, R remote\n"); vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type"); } /* Display all L2-VNIs */ hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb, &wctx); + + 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); + } } void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail) { - json_object *json = NULL; + json_object *json_array = NULL; zebra_evpn_t *zevpn; zevpn = zebra_evpn_lookup(vni); + if (uj) + json_array = json_object_new_array(); + if (zevpn) { - if (!detail && !json) { + if (!detail && !json_array) { vty_out(vty, "Type: L local, R remote\n"); vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type"); } @@ -363,7 +417,15 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail) return; } - zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json, detail); + + zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail); + + 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); + } } /* Initialize the ES tables maintained per-L2_VNI */ @@ -691,6 +753,37 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif) zebra_evpn_acc_bd_free_on_deref(acc_bd); } +static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd *acc_bd, + json_object *json, bool detail) +{ + json_object_int_add(json, "vlan", acc_bd->vid); + if (acc_bd->vxlan_zif) + json_object_string_add(json, "vxlanIf", + acc_bd->vxlan_zif->ifp->name); + if (acc_bd->zevpn) + json_object_int_add(json, "vni", acc_bd->zevpn->vni); + if (acc_bd->mbr_zifs) + json_object_int_add(json, "memberIfCount", + listcount(acc_bd->mbr_zifs)); + + if (detail) { + json_object *json_mbrs; + json_object *json_mbr; + struct zebra_if *zif; + struct listnode *node; + + + json_mbrs = json_object_new_array(); + for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) { + json_mbr = json_object_new_object(); + json_object_string_add(json_mbr, "ifName", + zif->ifp->name); + json_object_array_add(json_mbrs, json_mbr); + } + json_object_object_add(json, "members", json_mbrs); + } +} + static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty, struct zebra_evpn_access_bd *acc_bd, json_object *json) { @@ -698,7 +791,7 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty, struct listnode *node; if (json) { - /* XXX */ + zebra_evpn_acc_vl_json_fill(acc_bd, json, true); } else { vty_out(vty, "VLAN: %u\n", acc_bd->vid); vty_out(vty, " VxLAN Interface: %s\n", @@ -718,58 +811,83 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty, static void zebra_evpn_acc_vl_show_entry(struct vty *vty, struct zebra_evpn_access_bd *acc_bd, json_object *json) { - if (!json) + if (json) { + zebra_evpn_acc_vl_json_fill(acc_bd, json, false); + } else { vty_out(vty, "%-5u %21s %-8d %u\n", acc_bd->vid, acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-", acc_bd->zevpn ? acc_bd->zevpn->vni : 0, listcount(acc_bd->mbr_zifs)); + } } static void zebra_evpn_acc_vl_show_hash(struct hash_bucket *bucket, void *ctxt) { struct evpn_mh_show_ctx *wctx = ctxt; struct zebra_evpn_access_bd *acc_bd = bucket->data; + json_object *json = NULL; + if (wctx->json) + json = json_object_new_object(); if (wctx->detail) - zebra_evpn_acc_vl_show_entry_detail(wctx->vty, - acc_bd, wctx->json); + zebra_evpn_acc_vl_show_entry_detail(wctx->vty, acc_bd, json); else - zebra_evpn_acc_vl_show_entry(wctx->vty, - acc_bd, wctx->json); + zebra_evpn_acc_vl_show_entry(wctx->vty, acc_bd, json); + if (json) + json_object_array_add(wctx->json, json); } void zebra_evpn_acc_vl_show(struct vty *vty, bool uj) { - json_object *json = NULL; struct evpn_mh_show_ctx wctx; + json_object *json_array = NULL; + + if (uj) + json_array = json_object_new_array(); memset(&wctx, 0, sizeof(wctx)); wctx.vty = vty; - wctx.json = json; + wctx.json = json_array; wctx.detail = false; - if (!json) + if (!uj) vty_out(vty, "%-5s %21s %-8s %s\n", "VLAN", "VxLAN-IF", "L2-VNI", "# Members"); hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash, &wctx); + + 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); + } } void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj) { - json_object *json = NULL; struct evpn_mh_show_ctx wctx; + json_object *json_array = NULL; + if (uj) + json_array = json_object_new_array(); memset(&wctx, 0, sizeof(wctx)); wctx.vty = vty; - wctx.json = json; + wctx.json = json_array; wctx.detail = true; hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash, &wctx); + + 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); + } } void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid) @@ -777,14 +895,23 @@ void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid) json_object *json = NULL; struct zebra_evpn_access_bd *acc_bd; + if (uj) + json = json_object_new_object(); + acc_bd = zebra_evpn_acc_vl_find(vid); - if (!acc_bd) { - if (!json) { + if (acc_bd) { + zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json); + } else { + if (!json) vty_out(vty, "VLAN %u not present\n", vid); - return; - } } - zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* Initialize VLAN member bitmap on an interface. Although VLAN membership @@ -2073,14 +2200,69 @@ static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es, return vtep_str; } -static void zebra_evpn_es_show_entry(struct vty *vty, - struct zebra_evpn_es *es, json_object *json) +static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es, + json_object *json_vteps) +{ + struct zebra_evpn_es_vtep *es_vtep; + struct listnode *node; + json_object *json_vtep_entry; + char alg_buf[EVPN_DF_ALG_STR_LEN]; + + for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { + json_vtep_entry = json_object_new_object(); + json_object_string_add(json_vtep_entry, "vtep", + inet_ntoa(es_vtep->vtep_ip)); + if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) { + json_object_string_add( + json_vtep_entry, "dfAlgorithm", + evpn_es_df_alg2str(es_vtep->df_alg, alg_buf, + sizeof(alg_buf))); + json_object_int_add(json_vtep_entry, "dfPreference", + es_vtep->df_pref); + } + json_object_int_add(json_vtep_entry, "nexthopId", + es_vtep->nh_id); + json_object_array_add(json_vteps, json_vtep_entry); + } +} + +static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es, + json_object *json_array) { char type_str[4]; char vtep_str[ES_VTEP_LIST_STR_SZ]; - if (json) { - /* XXX */ + if (json_array) { + json_object *json = NULL; + json_object *json_vteps; + json_object *json_flags; + + json = json_object_new_object(); + json_object_string_add(json, "esi", es->esi_str); + + if (es->flags + & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE + | ZEBRA_EVPNES_NON_DF)) { + json_flags = json_object_new_array(); + if (es->flags & ZEBRA_EVPNES_LOCAL) + json_array_string_add(json_flags, "local"); + if (es->flags & ZEBRA_EVPNES_REMOTE) + json_array_string_add(json_flags, "remote"); + if (es->flags & ZEBRA_EVPNES_NON_DF) + json_array_string_add(json_flags, "nonDF"); + json_object_object_add(json, "flags", json_flags); + } + + if (es->zif) + json_object_string_add(json, "accessPort", + es->zif->ifp->name); + + if (listcount(es->es_vtep_list)) { + json_vteps = json_object_new_array(); + zebra_evpn_es_json_vtep_fill(es, json_vteps); + json_object_object_add(json, "vteps", json_vteps); + } + json_object_array_add(json_array, json); } else { type_str[0] = '\0'; if (es->flags & ZEBRA_EVPNES_LOCAL) @@ -2108,7 +2290,46 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty, struct listnode *node; if (json) { - /* XXX */ + json_object *json_vteps; + json_object *json_flags; + + json_object_string_add(json, "esi", es->esi_str); + if (es->zif) + json_object_string_add(json, "accessPort", + es->zif->ifp->name); + + + if (es->flags) { + json_flags = json_object_new_array(); + if (es->flags & ZEBRA_EVPNES_LOCAL) + json_array_string_add(json_flags, "local"); + if (es->flags & ZEBRA_EVPNES_REMOTE) + json_array_string_add(json_flags, "remote"); + if (es->flags & ZEBRA_EVPNES_NON_DF) + json_array_string_add(json_flags, "nonDF"); + if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) + json_array_string_add(json_flags, + "readyForBgp"); + if (es->flags & ZEBRA_EVPNES_BR_PORT) + json_array_string_add(json_flags, "bridgePort"); + if (es->flags & ZEBRA_EVPNES_OPER_UP) + json_array_string_add(json_flags, "operUp"); + if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) + json_array_string_add(json_flags, + "nexthopGroupActive"); + json_object_object_add(json, "flags", json_flags); + } + + json_object_int_add(json, "vniCount", + listcount(es->es_evi_list)); + json_object_int_add(json, "macCount", listcount(es->mac_list)); + json_object_int_add(json, "dfPreference", es->df_pref); + json_object_int_add(json, "nexthopGroup", es->nhg_id); + if (listcount(es->es_vtep_list)) { + json_vteps = json_object_new_array(); + zebra_evpn_es_json_vtep_fill(es, json_vteps); + json_object_object_add(json, "vteps", json_vteps); + } } else { type_str[0] = '\0'; if (es->flags & ZEBRA_EVPNES_LOCAL) @@ -2161,10 +2382,10 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty, void zebra_evpn_es_show(struct vty *vty, bool uj) { struct zebra_evpn_es *es; - json_object *json = NULL; + json_object *json_array = NULL; if (uj) { - /* XXX */ + json_array = json_object_new_array(); } else { vty_out(vty, "Type: L local, R remote, N non-DF\n"); vty_out(vty, "%-30s %-4s %-21s %s\n", @@ -2172,16 +2393,40 @@ void zebra_evpn_es_show(struct vty *vty, bool uj) } RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree) - zebra_evpn_es_show_entry(vty, es, json); + zebra_evpn_es_show_entry(vty, es, json_array); + + 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); + } } void zebra_evpn_es_show_detail(struct vty *vty, bool uj) { struct zebra_evpn_es *es; - json_object *json = NULL; + json_object *json_array = NULL; - RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree) + if (uj) + json_array = json_object_new_array(); + + RB_FOREACH (es, zebra_es_rb_head, &zmh_info->es_rb_tree) { + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); zebra_evpn_es_show_entry_detail(vty, es, json); + if (uj) + json_object_array_add(json_array, json); + } + + 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); + } } void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi) @@ -2190,15 +2435,26 @@ void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi) char esi_str[ESI_STR_LEN]; json_object *json = NULL; + if (uj) + json = json_object_new_object(); + es = zebra_evpn_es_find(esi); - if (!es) { - esi_to_str(esi, esi_str, sizeof(esi_str)); - vty_out(vty, "ESI %s does not exist\n", esi_str); - return; + if (es) { + zebra_evpn_es_show_entry_detail(vty, es, json); + } else { + if (!uj) { + esi_to_str(esi, esi_str, sizeof(esi_str)); + vty_out(vty, "ESI %s does not exist\n", esi_str); + } } - zebra_evpn_es_show_entry_detail(vty, es, json); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 1a6e6032b6..68a96b61c2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2596,7 +2596,7 @@ DEFUN (show_evpn_global, DEFPY(show_evpn_es, show_evpn_es_cmd, - "show evpn es [NAME$esi_str] [json$json] [detail$detail]", + "show evpn es [NAME$esi_str|detail$detail] [json$json]", SHOW_STR "EVPN\n" "Ethernet Segment\n" @@ -2625,14 +2625,14 @@ DEFPY(show_evpn_es, DEFPY(show_evpn_es_evi, show_evpn_es_evi_cmd, - "show evpn es-evi [vni (1-16777215)$vni] [json$json] [detail$detail]", + "show evpn es-evi [vni (1-16777215)$vni] [detail$detail] [json$json]", SHOW_STR "EVPN\n" "Ethernet Segment per EVI\n" "VxLAN Network Identifier\n" "VNI\n" - JSON_STR - "Detailed information\n") + "Detailed information\n" + JSON_STR) { bool uj = !!json; bool ud = !!detail; @@ -2647,13 +2647,13 @@ DEFPY(show_evpn_es_evi, DEFPY(show_evpn_access_vlan, show_evpn_access_vlan_cmd, - "show evpn access-vlan [(1-4094)$vid] [json$json] [detail$detail]", + "show evpn access-vlan [(1-4094)$vid | detail$detail] [json$json]", SHOW_STR "EVPN\n" "Access VLANs\n" "VLAN ID\n" - JSON_STR - "Detailed information\n") + "Detailed information\n" + JSON_STR) { bool uj = !!json;