]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Add CLI to display SRv6 SIDs allocated
authorCarmine Scarpitta <cscarpit@cisco.com>
Sun, 15 Sep 2024 20:33:39 +0000 (22:33 +0200)
committerCarmine Scarpitta <cscarpit@cisco.com>
Sat, 19 Apr 2025 10:59:38 +0000 (10:59 +0000)
```
router# show segment-routing srv6 sid
 SID                   Behavior    Context                Daemon/Instance    Locator    Allocation Type
 --------------------  ----------  ---------------------  -----------------  ---------  -----------------
 fcbb:bbbb:1::         uN          -                      isis(0)            MAIN       dynamic
 fcbb:bbbb:1:fe00::    uDT6        VRF 'vrf10'            bgp(0)             MAIN       dynamic
 fcbb:bbbb:1:fe01::    uDT6        VRF 'vrf20'            bgp(0)             MAIN       dynamic
 fcbb:bbbb:1:e000::    uA          Interface 'eth-sw1'    isis(0)            MAIN       dynamic
 fcbb:bbbb:1:e001::    uA          Interface 'eth-sw1'    isis(0)            MAIN       dynamic
```

```
router# show segment-routing srv6 sid json
{
  "fc00:0:1::":{
    "sid":"fc00:0:1::",
    "behavior":"uN",
    "context":{},
    "locator":"loc1",
    "allocationMode":"dynamic",
    "clients":[
      {
        "proto":"isis",
        "instance":0
      }
    ]
  },
  "fc00:0:1:1::":{
    "sid":"fc00:0:1:1::",
    "behavior":"uA",
    "context":{
      "interfaceIndex":2,
      "interfaceName":"eth-sw1",
      "nexthopIpv6Address":"fe80::4423:f3ff:fe8b:fed"
    },
    "locator":"loc1",
    "allocationMode":"dynamic",
    "clients":[
      {
        "proto":"isis",
        "instance":0
      }
    ]
  },
  "fc00:0:1:2::":{
    "sid":"fc00:0:1:2::",
    "behavior":"uA",
    "context":{
      "interfaceIndex":2,
      "interfaceName":"eth-sw1",
      "nexthopIpv6Address":"fe80::9005:fdff:fe18:1237"
    },
    "locator":"loc1",
    "allocationMode":"dynamic",
    "clients":[
      {
        "proto":"isis",
        "instance":0
      }
    ]
  }
}
```

Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
zebra/zebra_srv6_vty.c

index 3d5a76ff389118c8b2d25a1b49ae9822200c568f..3ecc8b39ab8a54abf9bfdb6d66053fb850163659 100644 (file)
@@ -16,6 +16,7 @@
 #include "vrf.h"
 #include "srv6.h"
 #include "lib/json.h"
+#include "termtable.h"
 
 #include "zebra/zserv.h"
 #include "zebra/zebra_router.h"
@@ -258,6 +259,401 @@ DEFUN (show_srv6_locator_detail,
        return CMD_SUCCESS;
 }
 
+static const char *show_srv6_sid_seg6_action(enum seg6local_action_t behavior)
+{
+       switch (behavior) {
+       case ZEBRA_SEG6_LOCAL_ACTION_END:
+               return "uN";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+               return "uA";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+               return "uDX6";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+               return "uDX4";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+               return "uDT6";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+               return "uDT4";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
+               return "uDT46";
+       case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+               return "unspec";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_BPF:
+               break;
+       }
+
+       return "unknown";
+}
+
+static const char *show_srv6_sid_seg6_context(char *str, size_t size, const struct srv6_sid_ctx *ctx,
+                                             enum seg6local_action_t behavior)
+{
+       struct vrf *vrf;
+       struct interface *ifp;
+
+       switch (behavior) {
+       case ZEBRA_SEG6_LOCAL_ACTION_END:
+               break;
+       case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+               RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+                       ifp = if_lookup_by_index(ctx->ifindex, vrf->vrf_id);
+                       if (ifp)
+                               snprintf(str, size, "Interface '%s'", ifp->name);
+               }
+               break;
+       case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
+               vrf = vrf_lookup_by_id(ctx->vrf_id);
+               snprintf(str, size, "VRF '%s'", vrf ? vrf->name : "<unknown>");
+               break;
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_BPF:
+       case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+               break;
+       }
+
+       return str;
+}
+
+static void do_show_srv6_sid_line(struct ttable *tt, struct zebra_srv6_sid *sid)
+{
+       struct listnode *node;
+       struct zserv *client;
+       char clients[256];
+       char ctx[256] = {};
+       char behavior[256] = {};
+       char alloc_mode_str[10] = {};
+       char locator_name[SRV6_LOCNAME_SIZE];
+       int ret;
+
+       /* Zclients */
+       if (listcount(sid->client_list)) {
+               bool first = true;
+               int i = 0;
+               for (ALL_LIST_ELEMENTS_RO(sid->client_list, node, client)) {
+                       if (first) {
+                               ret = snprintf(clients + i, sizeof(clients) - i, "%s(%d)",
+                                              zebra_route_string(client->proto), client->instance);
+                               first = false;
+                       } else {
+                               ret = snprintf(clients + i, sizeof(clients) - i, ", %s(%d)",
+                                              zebra_route_string(client->proto), client->instance);
+                       }
+
+                       if (ret > 0)
+                               i += ret;
+               }
+       }
+
+       /* Behavior */
+       if (sid->locator) {
+               if ((sid->locator->sid_format &&
+                    sid->locator->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) ||
+                   (!sid->locator->sid_format &&
+                    CHECK_FLAG(sid->locator->flags, SRV6_LOCATOR_USID))) {
+                       snprintf(behavior, sizeof(behavior), "%s",
+                                show_srv6_sid_seg6_action(sid->ctx->ctx.behavior));
+               } else {
+                       snprintf(behavior, sizeof(behavior), "%s",
+                                seg6local_action2str(sid->ctx->ctx.behavior));
+               }
+       }
+
+       /* SID context */
+       show_srv6_sid_seg6_context(ctx, sizeof(ctx), &sid->ctx->ctx, sid->ctx->ctx.behavior);
+
+       if (strlen(ctx) == 0)
+               snprintf(ctx, sizeof(ctx), "-");
+
+       if (sid->locator)
+               snprintf(locator_name, sizeof(locator_name), "%s", sid->locator->name);
+       else
+               snprintf(locator_name, sizeof(locator_name), "-");
+
+       snprintf(alloc_mode_str, sizeof(alloc_mode_str), "%s",
+                srv6_sid_alloc_mode2str(sid->alloc_mode));
+
+       ttable_add_row(tt, "%pI6|%s|%s|%s|%s|%s", &sid->value, behavior, ctx, clients, locator_name,
+                      alloc_mode_str);
+}
+
+static void do_show_srv6_sid_json(struct vty *vty, json_object **json, struct srv6_locator *locator,
+                                 struct zebra_srv6_sid_ctx *sid_ctx)
+{
+       json_object *json_sid_ctx = NULL;
+       json_object *json_sid = NULL;
+       json_object *json_sid_clients = NULL;
+       json_object *json_sid_client = NULL;
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+       struct interface *ifp;
+       struct listnode *node;
+       struct zserv *client;
+       char buf[256];
+
+       if (!sid_ctx || !sid_ctx->sid)
+               return;
+
+       if (locator && sid_ctx->sid->locator != locator)
+               return;
+
+       json_sid = json_object_new_object();
+       json_sid_ctx = json_object_new_object();
+
+       json_object_string_addf(json_sid, "sid", "%pI6", &sid_ctx->sid->value);
+       if ((sid_ctx->sid->locator->sid_format &&
+            sid_ctx->sid->locator->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) ||
+           (!sid_ctx->sid->locator->sid_format &&
+            CHECK_FLAG(sid_ctx->sid->locator->flags, SRV6_LOCATOR_USID))) {
+               json_object_string_add(json_sid, "behavior",
+                                      show_srv6_sid_seg6_action(sid_ctx->ctx.behavior));
+       } else {
+               json_object_string_add(json_sid, "behavior",
+                                      seg6local_action2str(sid_ctx->ctx.behavior));
+       }
+
+       if (sid_ctx->ctx.vrf_id) {
+               json_object_int_add(json_sid_ctx, "vrfId", sid_ctx->ctx.vrf_id);
+
+               vrf = vrf_lookup_by_id(sid_ctx->ctx.vrf_id);
+               if (vrf)
+                       json_object_string_add(json_sid_ctx, "vrfName", vrf->name);
+
+               zvrf = vrf_info_lookup(sid_ctx->ctx.vrf_id);
+               if (vrf)
+                       json_object_int_add(json_sid_ctx, "table", zvrf->table_id);
+       }
+       if (sid_ctx->ctx.ifindex) {
+               json_object_int_add(json_sid_ctx, "interfaceIndex", sid_ctx->ctx.ifindex);
+               RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+                       ifp = if_lookup_by_index(sid_ctx->ctx.ifindex, vrf->vrf_id);
+                       if (ifp)
+                               json_object_string_add(json_sid_ctx, "interfaceName", ifp->name);
+               }
+       }
+       if (memcmp(&sid_ctx->ctx.nh6, &in6addr_any, sizeof(struct in6_addr)) != 0) {
+               json_object_string_addf(json_sid_ctx, "nexthopIpv6Address", "%pI6",
+                                       &sid_ctx->ctx.nh6);
+       }
+       json_object_object_add(json_sid, "context", json_sid_ctx);
+
+       json_object_string_add(json_sid, "locator", sid_ctx->sid->locator->name);
+       json_object_string_add(json_sid, "allocationMode",
+                              srv6_sid_alloc_mode2str(sid_ctx->sid->alloc_mode));
+
+       /* Zclients */
+       json_sid_clients = json_object_new_array();
+       if (listcount(sid_ctx->sid->client_list)) {
+               for (ALL_LIST_ELEMENTS_RO(sid_ctx->sid->client_list, node, client)) {
+                       json_sid_client = json_object_new_object();
+                       json_object_string_add(json_sid_client, "protocol",
+                                              zebra_route_string(client->proto));
+                       json_object_int_add(json_sid_client, "instance", client->instance);
+                       json_object_array_add(json_sid_clients, json_sid_client);
+               }
+       }
+       json_object_object_add(json_sid, "clients", json_sid_clients);
+
+       json_object_object_add(*json, inet_ntop(AF_INET6, &sid_ctx->sid->value, buf, sizeof(buf)),
+                              json_sid);
+}
+
+static void do_show_srv6_sid_specific(struct vty *vty, json_object **json,
+                                     struct srv6_locator *locator,
+                                     struct zebra_srv6_sid_ctx *sid_ctx)
+{
+       struct ttable *tt;
+
+       if (json) {
+               do_show_srv6_sid_json(vty, json, locator, sid_ctx);
+       } else {
+               /* Prepare table. */
+               tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+
+               ttable_add_row(tt, "SID|Behavior|Context|Daemon/Instance|Locator|AllocationType");
+               tt->style.cell.rpad = 2;
+               tt->style.corner = ' ';
+               ttable_restyle(tt);
+               ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+               if (!sid_ctx || !sid_ctx->sid)
+                       return;
+
+               if (locator && sid_ctx->sid->locator != locator)
+                       return;
+
+               do_show_srv6_sid_line(tt, sid_ctx->sid);
+
+               ttable_colseps(tt, 1, RIGHT, true, ' ');
+               ttable_colseps(tt, 2, LEFT, true, ' ');
+               ttable_colseps(tt, 2, RIGHT, true, ' ');
+               ttable_colseps(tt, 3, LEFT, true, ' ');
+               ttable_colseps(tt, 3, RIGHT, true, ' ');
+               ttable_colseps(tt, 4, LEFT, true, ' ');
+               ttable_colseps(tt, 4, RIGHT, true, ' ');
+               ttable_colseps(tt, 5, LEFT, true, ' ');
+
+               /* Dump the generated table. */
+               if (tt->nrows > 1) {
+                       char *table;
+
+                       table = ttable_dump(tt, "\n");
+                       vty_out(vty, "%s\n", table);
+                       XFREE(MTYPE_TMP_TTABLE, table);
+               }
+               ttable_del(tt);
+       }
+}
+
+static void do_show_srv6_sid_all(struct vty *vty, json_object **json, struct srv6_locator *locator)
+{
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct zebra_srv6_sid_ctx *ctx;
+       struct listnode *node;
+       struct ttable *tt;
+
+       if (json) {
+               for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, ctx)) {
+                       /* Skip contexts not associated with any SID */
+                       if (!ctx->sid)
+                               continue;
+
+                       /* Skip SIDs from locators we are not interested in */
+                       if (locator && ctx->sid->locator != locator)
+                               continue;
+
+                       do_show_srv6_sid_json(vty, json, locator, ctx);
+               }
+       } else {
+               /* Prepare table. */
+               tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+               ttable_add_row(tt, "SID|Behavior|Context|Daemon/Instance|Locator|AllocationType");
+               tt->style.cell.rpad = 2;
+               tt->style.corner = ' ';
+               ttable_restyle(tt);
+               ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+               for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, ctx)) {
+                       /* Skip contexts not associated with any SID */
+                       if (!ctx->sid)
+                               continue;
+
+                       /* Skip SIDs from locators we are not interested in */
+                       if (locator && ctx->sid->locator != locator)
+                               continue;
+
+                       do_show_srv6_sid_line(tt, ctx->sid);
+               }
+
+               ttable_colseps(tt, 1, RIGHT, true, ' ');
+               ttable_colseps(tt, 2, LEFT, true, ' ');
+               ttable_colseps(tt, 2, RIGHT, true, ' ');
+               ttable_colseps(tt, 3, LEFT, true, ' ');
+               ttable_colseps(tt, 3, RIGHT, true, ' ');
+               ttable_colseps(tt, 4, LEFT, true, ' ');
+               ttable_colseps(tt, 4, RIGHT, true, ' ');
+               ttable_colseps(tt, 5, LEFT, true, ' ');
+
+               /* Dump the generated table. */
+               if (tt->nrows > 1) {
+                       char *table;
+
+                       table = ttable_dump(tt, "\n");
+                       vty_out(vty, "%s\n", table);
+                       XFREE(MTYPE_TMP_TTABLE, table);
+               }
+               ttable_del(tt);
+       }
+}
+
+DEFPY (show_srv6_sid,
+       show_srv6_sid_cmd,
+       "show segment-routing srv6 [locator NAME$locator_name] sid [X:X::X:X$sid_value] [json]",
+       SHOW_STR
+       "Segment Routing\n"
+       "Segment Routing SRv6\n"
+       "Locator Information\n"
+       "Locator Name\n"
+       "SID\n"
+       "SID value\n"
+       JSON_STR)
+{
+       bool uj = use_json(argc, argv);
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct srv6_locator *locator = NULL;
+       struct zebra_srv6_sid_ctx *sid_ctx = NULL, *c;
+       struct listnode *node;
+       json_object *json = NULL;
+
+       if (uj)
+               json = json_object_new_object();
+
+       if (locator_name) {
+               locator = zebra_srv6_locator_lookup(locator_name);
+               if (!locator) {
+                       if (uj)
+                               vty_json(vty, json); /* Return empty json */
+                       else
+                               vty_out(vty, "%% Can't find the SRv6 locator\n");
+                       return CMD_WARNING;
+               }
+       }
+
+       if (!IPV6_ADDR_SAME(&sid_value, &in6addr_any)) {
+               for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, c)) {
+                       if (c->sid && IPV6_ADDR_SAME(&c->sid->value, &sid_value)) {
+                               sid_ctx = c;
+                               break;
+                       }
+               }
+
+               if (!sid_ctx) {
+                       if (uj)
+                               vty_json(vty, json); /* Return empty json */
+                       else
+                               vty_out(vty, "%% Can't find the SRv6 SID\n");
+                       return CMD_WARNING;
+               }
+       }
+
+       if (locator && sid_ctx)
+               if (!sid_ctx->sid || sid_ctx->sid->locator != locator) {
+                       if (uj)
+                               vty_json(vty, json); /* Return empty json */
+                       else
+                               vty_out(vty, "%% Can't find the SRv6 SID in the provided locator\n");
+                       return CMD_WARNING;
+               }
+
+       if (sid_ctx)
+               do_show_srv6_sid_specific(vty, uj ? &json : NULL, locator, sid_ctx);
+       else
+               do_show_srv6_sid_all(vty, uj ? &json : NULL, locator);
+
+       if (uj)
+               vty_json(vty, json);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN_NOSH (segment_routing,
             segment_routing_cmd,
             "segment-routing",
@@ -1115,4 +1511,5 @@ void zebra_srv6_vty_init(void)
        install_element(VIEW_NODE, &show_srv6_locator_cmd);
        install_element(VIEW_NODE, &show_srv6_locator_detail_cmd);
        install_element(VIEW_NODE, &show_srv6_manager_cmd);
+       install_element(VIEW_NODE, &show_srv6_sid_cmd);
 }