diff options
Diffstat (limited to 'zebra/zebra_vty.c')
| -rw-r--r-- | zebra/zebra_vty.c | 351 |
1 files changed, 262 insertions, 89 deletions
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 4ca5b45c36..2ea04eee2e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -44,6 +44,7 @@ #include "zebra/zebra_routemap.h" #include "lib/json.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_evpn_mh.h" #ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_vty_clippy.c" #endif @@ -55,6 +56,7 @@ #include "zebra/zebra_nhg.h" #include "zebra/interface.h" #include "northbound_cli.h" +#include "zebra/zebra_nb.h" extern int allow_delete; @@ -71,6 +73,12 @@ static void vty_show_ip_route_summary(struct vty *vty, static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table, bool use_json); +/* Helper api to format a nexthop in the 'detailed' output path. */ +static void show_nexthop_detail_helper(struct vty *vty, + const struct route_entry *re, + const struct nexthop *nexthop, + bool is_backup); + DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, @@ -166,11 +174,24 @@ DEFUN (show_ip_rpf_addr, } static char re_status_output_char(const struct route_entry *re, - const struct nexthop *nhop) + const struct nexthop *nhop, + bool is_fib) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) { - if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) && - !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) + bool star_p = false; + + if (nhop && + !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) && + !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) { + /* More-specific test for 'fib' output */ + if (is_fib) { + star_p = !!CHECK_FLAG(nhop->flags, + NEXTHOP_FLAG_FIB); + } else + star_p = true; + } + + if (star_p) return '*'; else return ' '; @@ -190,19 +211,51 @@ static char re_status_output_char(const struct route_entry *re, } /* - * TODO -- Show backup nexthop info + * Show backup nexthop info, in the 'detailed' output path */ static void show_nh_backup_helper(struct vty *vty, - const struct nhg_hash_entry *nhe, + const struct route_entry *re, const struct nexthop *nexthop) { + const struct nexthop *start, *backup, *temp; + int i, idx; + /* Double-check that there _is_ a backup */ - if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) || + re->nhe->backup_info == NULL || re->nhe->backup_info->nhe == NULL || + re->nhe->backup_info->nhe->nhg.nexthop == NULL) return; - /* Locate the backup nexthop */ + /* Locate the backup nexthop(s) */ + start = re->nhe->backup_info->nhe->nhg.nexthop; + for (i = 0; i < nexthop->backup_num; i++) { + /* Format the backup(s) (indented) */ + backup = start; + for (idx = 0; idx < nexthop->backup_idx[i]; idx++) { + backup = backup->next; + if (backup == NULL) + break; + } - /* Format the backup (indented) */ + /* It's possible for backups to be recursive too, + * so walk the recursive resolution list if present. + */ + temp = backup; + while (backup) { + vty_out(vty, " "); + show_nexthop_detail_helper(vty, re, backup, + true /*backup*/); + vty_out(vty, "\n"); + + if (backup->resolved && temp == backup) + backup = backup->resolved; + else + backup = nexthop_next(backup); + + if (backup == temp->next) + break; + } + } } @@ -212,14 +265,20 @@ static void show_nh_backup_helper(struct vty *vty, */ static void show_nexthop_detail_helper(struct vty *vty, const struct route_entry *re, - const struct nexthop *nexthop) + const struct nexthop *nexthop, + bool is_backup) { char addrstr[32]; char buf[MPLS_LABEL_STRLEN]; + int i; - vty_out(vty, " %c%s", - re_status_output_char(re, nexthop), - nexthop->rparent ? " " : ""); + if (is_backup) + vty_out(vty, " b%s", + nexthop->rparent ? " " : ""); + else + vty_out(vty, " %c%s", + re_status_output_char(re, nexthop, false), + nexthop->rparent ? " " : ""); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -333,6 +392,13 @@ static void show_nexthop_detail_helper(struct vty *vty, if (nexthop->weight) vty_out(vty, ", weight %u", nexthop->weight); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + vty_out(vty, ", backup %d", nexthop->backup_idx[0]); + + for (i = 1; i < nexthop->backup_num; i++) + vty_out(vty, ",%d", nexthop->backup_idx[i]); + } } /* New RIB. Detailed information for IPv4 route. */ @@ -403,12 +469,13 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { /* Use helper to format each nexthop */ - show_nexthop_detail_helper(vty, re, nexthop); + show_nexthop_detail_helper(vty, re, nexthop, + false /*not backup*/); vty_out(vty, "\n"); - /* Include backup info, if present */ + /* Include backup(s), if present */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) - show_nh_backup_helper(vty, re->nhe, nexthop); + show_nh_backup_helper(vty, re, nexthop); } vty_out(vty, "\n"); } @@ -422,6 +489,7 @@ static void show_route_nexthop_helper(struct vty *vty, const struct nexthop *nexthop) { char buf[MPLS_LABEL_STRLEN]; + int i; switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -519,8 +587,12 @@ static void show_route_nexthop_helper(struct vty *vty, if (nexthop->weight) vty_out(vty, ", weight %u", nexthop->weight); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) - vty_out(vty, ", backup %d", nexthop->backup_idx); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + vty_out(vty, ", backup %d", nexthop->backup_idx[0]); + + for (i = 1; i < nexthop->backup_num; i++) + vty_out(vty, ",%d", nexthop->backup_idx[i]); + } } /* @@ -534,6 +606,8 @@ static void show_nexthop_json_helper(json_object *json_nexthop, char buf[SRCDEST2STR_BUFFER]; struct vrf *vrf = NULL; json_object *json_labels = NULL; + json_object *json_backups = NULL; + int i; json_object_int_add(json_nexthop, "flags", nexthop->flags); @@ -645,9 +719,17 @@ static void show_nexthop_json_helper(json_object *json_nexthop, json_object_boolean_true_add(json_nexthop, "recursive"); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) - json_object_int_add(json_nexthop, "backupIndex", - nexthop->backup_idx); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + json_backups = json_object_new_array(); + for (i = 0; i < nexthop->backup_num; i++) { + json_object_array_add( + json_backups, + json_object_new_int(nexthop->backup_idx[i])); + } + + json_object_object_add(json_nexthop, "backupIndex", + json_backups); + } switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -705,18 +787,19 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct route_entry *re, json_object *json, bool is_fib) { - struct nexthop *nexthop; + const struct nexthop *nexthop; int len = 0; char buf[SRCDEST2STR_BUFFER]; json_object *json_nexthops = NULL; json_object *json_nexthop = NULL; json_object *json_route = NULL; time_t uptime; - struct vrf *vrf = NULL; - rib_dest_t *dest = rib_dest_from_rnode(rn); - struct nexthop_group *nhg; + const struct vrf *vrf = NULL; + const rib_dest_t *dest = rib_dest_from_rnode(rn); + const struct nexthop_group *nhg; char up_str[MONOTIME_STRLEN]; - bool first_p; + bool first_p = true; + bool nhg_from_backup = false; uptime = monotime(NULL); uptime -= re->uptime; @@ -791,9 +874,11 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { json_nexthop = json_object_new_object(); + show_nexthop_json_helper(json_nexthop, + nexthop, re); - show_nexthop_json_helper(json_nexthop, nexthop, re); - json_object_array_add(json_nexthops, json_nexthop); + json_object_array_add(json_nexthops, + json_nexthop); } json_object_object_add(json_route, "nexthops", json_nexthops); @@ -804,7 +889,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, else nhg = zebra_nhg_get_backup_nhg(re->nhe); - if (nhg) { + if (nhg && nhg->nexthop) { json_nexthops = json_object_new_array(); for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { @@ -824,42 +909,62 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, return; } + /* Prefix information, and first nexthop. If we're showing 'fib', + * and there are no installed primary nexthops, see if there are any + * backup nexthops and start with those. + */ + if (is_fib && nhg->nexthop == NULL) { + nhg = rib_get_fib_backup_nhg(re); + nhg_from_backup = true; + } + + len = vty_out(vty, "%c", zebra_route_char(re->type)); + if (re->instance) + len += vty_out(vty, "[%d]", re->instance); + if (nhg_from_backup && nhg->nexthop) { + len += vty_out( + vty, "%cb%c %s", + CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', + re_status_output_char(re, nhg->nexthop, is_fib), + srcdest_rnode2str(rn, buf, sizeof(buf))); + } else { + len += vty_out( + vty, "%c%c %s", + CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', + re_status_output_char(re, nhg->nexthop, is_fib), + srcdest_rnode2str(rn, buf, sizeof(buf))); + } + + /* Distance and metric display. */ + if (((re->type == ZEBRA_ROUTE_CONNECT) && + (re->distance || re->metric)) || + (re->type != ZEBRA_ROUTE_CONNECT)) + len += vty_out(vty, " [%u/%u]", re->distance, + re->metric); + /* Nexthop information. */ - first_p = true; for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { if (first_p) { first_p = false; - - /* Prefix information. */ - len = vty_out(vty, "%c", zebra_route_char(re->type)); - if (re->instance) - len += vty_out(vty, "[%d]", re->instance); - len += vty_out( - vty, "%c%c %s", - CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) - ? '>' - : ' ', - re_status_output_char(re, nexthop), - srcdest_rnode2str(rn, buf, sizeof(buf))); - - /* Distance and metric display. */ - if (((re->type == ZEBRA_ROUTE_CONNECT) && - (re->distance || re->metric)) || - (re->type != ZEBRA_ROUTE_CONNECT)) - len += vty_out(vty, " [%u/%u]", re->distance, - re->metric); + } else if (nhg_from_backup) { + vty_out(vty, " b%c%*c", + re_status_output_char(re, nexthop, is_fib), + len - 3 + (2 * nexthop_level(nexthop)), ' '); } else { vty_out(vty, " %c%*c", - re_status_output_char(re, nexthop), + re_status_output_char(re, nexthop, is_fib), len - 3 + (2 * nexthop_level(nexthop)), ' '); } show_route_nexthop_helper(vty, re, nexthop); - vty_out(vty, ", %s\n", up_str); } - /* Check for backup info if present */ + /* If we only had backup nexthops, we're done */ + if (nhg_from_backup) + return; + + /* Check for backup nexthop info if present */ if (is_fib) nhg = rib_get_fib_backup_nhg(re); else @@ -1206,7 +1311,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) vty_out(vty, " [backup %d]", - nexthop->backup_idx); + nexthop->backup_idx[0]); vty_out(vty, "\n"); continue; @@ -1214,22 +1319,13 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) /* TODO -- print more useful backup info */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { - struct nexthop *backup; int i; - i = 0; - for (ALL_NEXTHOPS(nhe->backup_info->nhe->nhg, backup)) { - if (i == nexthop->backup_idx) - break; - i++; - } + vty_out(vty, "[backup"); + for (i = 0; i < nexthop->backup_num; i++) + vty_out(vty, " %d", nexthop->backup_idx[i]); - /* TODO */ - if (backup) - vty_out(vty, " [backup %d]", - nexthop->backup_idx); - else - vty_out(vty, " [backup INVALID]"); + vty_out(vty, "]"); } vty_out(vty, "\n"); @@ -2304,12 +2400,9 @@ DEFUN (vrf_vni_mapping, "VNI-ID\n" "prefix-routes-only\n") { - int ret = 0; int filter = 0; ZEBRA_DECLVAR_CONTEXT(vrf, zvrf); - vni_t vni = strtoul(argv[1]->arg, NULL, 10); - char err[ERR_STR_SZ]; assert(vrf); assert(zvrf); @@ -2317,14 +2410,15 @@ DEFUN (vrf_vni_mapping, if (argc == 3) filter = 1; - /* Mark as having FRR configuration */ - vrf_set_user_cfged(vrf); - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - filter, 1); - if (ret != 0) { - vty_out(vty, "%s\n", err); - return CMD_WARNING; - } + nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_MODIFY, + argv[1]->arg); + + if (filter) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", + NB_OP_MODIFY, "true"); + + nb_cli_apply_changes(vty, NULL); return CMD_SUCCESS; } @@ -2337,12 +2431,10 @@ DEFUN (no_vrf_vni_mapping, "VNI-ID\n" "prefix-routes-only\n") { - int ret = 0; int filter = 0; - char err[ERR_STR_SZ]; - vni_t vni = strtoul(argv[2]->arg, NULL, 10); ZEBRA_DECLVAR_CONTEXT(vrf, zvrf); + vni_t vni = strtoul(argv[1]->arg, NULL, 10); assert(vrf); assert(zvrf); @@ -2350,16 +2442,22 @@ DEFUN (no_vrf_vni_mapping, if (argc == 4) filter = 1; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, - ERR_STR_SZ, filter, 0); - if (ret != 0) { - vty_out(vty, "%s\n", err); + if (zvrf->l3vni != vni) { + vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, + zvrf->vrf->name); return CMD_WARNING; } - /* If no other FRR config for this VRF, mark accordingly. */ - if (!zebra_vrf_has_config(zvrf)) - vrf_reset_user_cfged(vrf); + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_DESTROY, + argv[2]->arg); + + if (filter) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", + NB_OP_DESTROY, "true"); + + nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL); + + nb_cli_apply_changes(vty, NULL); return CMD_SUCCESS; } @@ -2419,6 +2517,81 @@ DEFUN (show_evpn_global, return CMD_SUCCESS; } +DEFPY(show_evpn_es, + show_evpn_es_cmd, + "show evpn es [NAME$esi_str] [json$json] [detail$detail]", + SHOW_STR + "EVPN\n" + "Ethernet Segment\n" + "ES ID\n" + JSON_STR + "Detailed information\n") +{ + esi_t esi; + bool uj = !!json; + + if (esi_str) { + if (!str_to_esi(esi_str, &esi)) { + vty_out(vty, "%% Malformed ESI\n"); + return CMD_WARNING; + } + zebra_evpn_es_show_esi(vty, uj, &esi); + } else { + if (detail) + zebra_evpn_es_show_detail(vty, uj); + else + zebra_evpn_es_show(vty, uj); + } + + return CMD_SUCCESS; +} + +DEFPY(show_evpn_es_evi, + show_evpn_es_evi_cmd, + "show evpn es-evi [vni (1-16777215)$vni] [json$json] [detail$detail]", + SHOW_STR + "EVPN\n" + "Ethernet Segment per EVI\n" + "VxLAN Network Identifier\n" + "VNI\n" + JSON_STR + "Detailed information\n") +{ + bool uj = !!json; + bool ud = !!detail; + + if (vni) + zebra_evpn_es_evi_show_vni(vty, uj, vni, ud); + else + zebra_evpn_es_evi_show(vty, uj, ud); + + return CMD_SUCCESS; +} + +DEFPY(show_evpn_access_vlan, + show_evpn_access_vlan_cmd, + "show evpn access-vlan [(1-4094)$vid] [json$json] [detail$detail]", + SHOW_STR + "EVPN\n" + "Access VLANs\n" + "VLAN ID\n" + JSON_STR + "Detailed information\n") +{ + bool uj = !!json; + + if (vid) { + zebra_evpn_acc_vl_show_vid(vty, uj, vid); + } else { + if (detail) + zebra_evpn_acc_vl_show_detail(vty, uj); + else + zebra_evpn_acc_vl_show(vty, uj); + } + + return CMD_SUCCESS; +} + DEFUN (show_evpn_vni, show_evpn_vni_cmd, "show evpn vni [json]", @@ -3468,9 +3641,6 @@ static int config_write_table(struct vty *vty) /* IPForwarding configuration write function. */ static int config_write_forwarding(struct vty *vty) { - /* FIXME: Find better place for that. */ - router_id_write(vty); - if (!ipforward()) vty_out(vty, "no ip forwarding\n"); if (!ipforward_ipv6()) @@ -3640,6 +3810,9 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_vni_cmd); install_element(VIEW_NODE, &show_evpn_vni_detail_cmd); install_element(VIEW_NODE, &show_evpn_vni_vni_cmd); + install_element(VIEW_NODE, &show_evpn_es_cmd); + install_element(VIEW_NODE, &show_evpn_es_evi_cmd); + install_element(VIEW_NODE, &show_evpn_access_vlan_cmd); install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd); install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd); install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd); |
