Coverage Report

Created: 2026-09-08 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/zebra_srv6_vty.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Zebra SRv6 VTY functions
4
 * Copyright (C) 2020  Hiroki Shirokura, LINE Corporation
5
 */
6
7
#include <zebra.h>
8
9
#include "memory.h"
10
#include "if.h"
11
#include "prefix.h"
12
#include "command.h"
13
#include "table.h"
14
#include "rib.h"
15
#include "nexthop.h"
16
#include "vrf.h"
17
#include "srv6.h"
18
#include "lib/json.h"
19
20
#include "zebra/zserv.h"
21
#include "zebra/zebra_router.h"
22
#include "zebra/zebra_vrf.h"
23
#include "zebra/zebra_srv6.h"
24
#include "zebra/zebra_srv6_vty.h"
25
#include "zebra/zebra_rnh.h"
26
#include "zebra/redistribute.h"
27
#include "zebra/zebra_routemap.h"
28
#include "zebra/zebra_dplane.h"
29
30
#include "zebra/zebra_srv6_vty_clippy.c"
31
32
static int zebra_sr_config(struct vty *vty);
33
34
static struct cmd_node sr_node = {
35
  .name = "sr",
36
  .node = SEGMENT_ROUTING_NODE,
37
  .parent_node = CONFIG_NODE,
38
  .prompt = "%s(config-sr)# ",
39
  .config_write = zebra_sr_config,
40
};
41
42
static struct cmd_node srv6_node = {
43
  .name = "srv6",
44
  .node = SRV6_NODE,
45
  .parent_node = SEGMENT_ROUTING_NODE,
46
  .prompt = "%s(config-srv6)# ",
47
48
};
49
50
static struct cmd_node srv6_locs_node = {
51
  .name = "srv6-locators",
52
  .node = SRV6_LOCS_NODE,
53
  .parent_node = SRV6_NODE,
54
  .prompt = "%s(config-srv6-locators)# ",
55
};
56
57
static struct cmd_node srv6_loc_node = {
58
  .name = "srv6-locator",
59
  .node = SRV6_LOC_NODE,
60
  .parent_node = SRV6_LOCS_NODE,
61
  .prompt = "%s(config-srv6-locator)# "
62
};
63
64
DEFUN (show_srv6_locator,
65
       show_srv6_locator_cmd,
66
       "show segment-routing srv6 locator [json]",
67
       SHOW_STR
68
       "Segment Routing\n"
69
       "Segment Routing SRv6\n"
70
       "Locator Information\n"
71
       JSON_STR)
72
0
{
73
0
  const bool uj = use_json(argc, argv);
74
0
  struct zebra_srv6 *srv6 = zebra_srv6_get_default();
75
0
  struct srv6_locator *locator;
76
0
  struct listnode *node;
77
0
  char str[256];
78
0
  int id;
79
0
  json_object *json = NULL;
80
0
  json_object *json_locators = NULL;
81
0
  json_object *json_locator = NULL;
82
83
0
  if (uj) {
84
0
    json = json_object_new_object();
85
0
    json_locators = json_object_new_array();
86
0
    json_object_object_add(json, "locators", json_locators);
87
88
0
    for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
89
0
      json_locator = srv6_locator_json(locator);
90
0
      if (!json_locator)
91
0
        continue;
92
0
      json_object_array_add(json_locators, json_locator);
93
94
0
    }
95
96
0
    vty_json(vty, json);
97
0
  } else {
98
0
    vty_out(vty, "Locator:\n");
99
0
    vty_out(vty, "Name                 ID      Prefix                   Status\n");
100
0
    vty_out(vty, "-------------------- ------- ------------------------ -------\n");
101
102
0
    id = 1;
103
0
    for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
104
0
      prefix2str(&locator->prefix, str, sizeof(str));
105
0
      vty_out(vty, "%-20s %7d %-24s %s\n",
106
0
        locator->name, id, str,
107
0
        locator->status_up ? "Up" : "Down");
108
0
      ++id;
109
0
    }
110
0
    vty_out(vty, "\n");
111
0
  }
112
113
0
  return CMD_SUCCESS;
114
0
}
115
116
DEFUN (show_srv6_locator_detail,
117
       show_srv6_locator_detail_cmd,
118
       "show segment-routing srv6 locator NAME detail [json]",
119
       SHOW_STR
120
       "Segment Routing\n"
121
       "Segment Routing SRv6\n"
122
       "Locator Information\n"
123
       "Locator Name\n"
124
       "Detailed information\n"
125
       JSON_STR)
126
0
{
127
0
  const bool uj = use_json(argc, argv);
128
0
  struct zebra_srv6 *srv6 = zebra_srv6_get_default();
129
0
  struct srv6_locator *locator;
130
0
  struct listnode *node;
131
0
  char str[256];
132
0
  const char *locator_name = argv[4]->arg;
133
0
  json_object *json_locator = NULL;
134
135
0
  if (uj) {
136
0
    locator = zebra_srv6_locator_lookup(locator_name);
137
0
    if (!locator)
138
0
      return CMD_WARNING;
139
140
0
    json_locator = srv6_locator_detailed_json(locator);
141
0
    vty_json(vty, json_locator);
142
0
    return CMD_SUCCESS;
143
0
  }
144
145
0
  for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
146
0
    struct listnode *node;
147
0
    struct srv6_locator_chunk *chunk;
148
149
0
    if (strcmp(locator->name, locator_name) != 0)
150
0
      continue;
151
152
0
    prefix2str(&locator->prefix, str, sizeof(str));
153
0
    vty_out(vty, "Name: %s\n", locator->name);
154
0
    vty_out(vty, "Prefix: %s\n", str);
155
0
    vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length);
156
0
    vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length);
157
0
    vty_out(vty, "Function-Bit-Len: %u\n",
158
0
      locator->function_bits_length);
159
0
    vty_out(vty, "Argument-Bit-Len: %u\n",
160
0
      locator->argument_bits_length);
161
162
0
    if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
163
0
      vty_out(vty, "Behavior: uSID\n");
164
165
0
    vty_out(vty, "Chunks:\n");
166
0
    for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node,
167
0
            chunk)) {
168
0
      prefix2str(&chunk->prefix, str, sizeof(str));
169
0
      vty_out(vty, "- prefix: %s, owner: %s\n", str,
170
0
        zebra_route_string(chunk->proto));
171
0
    }
172
0
  }
173
174
175
0
  return CMD_SUCCESS;
176
0
}
177
178
DEFUN_NOSH (segment_routing,
179
            segment_routing_cmd,
180
            "segment-routing",
181
            "Segment Routing\n")
182
0
{
183
0
  vty->node = SEGMENT_ROUTING_NODE;
184
0
  return CMD_SUCCESS;
185
0
}
186
187
DEFUN_NOSH (srv6,
188
            srv6_cmd,
189
            "srv6",
190
            "Segment Routing SRv6\n")
191
0
{
192
0
  vty->node = SRV6_NODE;
193
0
  return CMD_SUCCESS;
194
0
}
195
196
DEFUN (no_srv6,
197
       no_srv6_cmd,
198
       "no srv6",
199
       NO_STR
200
       "Segment Routing SRv6\n")
201
0
{
202
0
  struct zebra_srv6 *srv6 = zebra_srv6_get_default();
203
0
  struct srv6_locator *locator;
204
0
  struct listnode *node, *nnode;
205
206
0
  for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator))
207
0
    zebra_srv6_locator_delete(locator);
208
0
  return CMD_SUCCESS;
209
0
}
210
211
DEFUN_NOSH (srv6_locators,
212
            srv6_locators_cmd,
213
            "locators",
214
            "Segment Routing SRv6 locators\n")
215
0
{
216
0
  vty->node = SRV6_LOCS_NODE;
217
0
  return CMD_SUCCESS;
218
0
}
219
220
DEFUN_NOSH (srv6_locator,
221
            srv6_locator_cmd,
222
            "locator WORD",
223
            "Segment Routing SRv6 locator\n"
224
            "Specify locator-name\n")
225
0
{
226
0
  struct srv6_locator *locator = NULL;
227
228
0
  locator = zebra_srv6_locator_lookup(argv[1]->arg);
229
0
  if (locator) {
230
0
    VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator);
231
0
    locator->status_up = true;
232
0
    return CMD_SUCCESS;
233
0
  }
234
235
0
  locator = srv6_locator_alloc(argv[1]->arg);
236
0
  if (!locator) {
237
0
    vty_out(vty, "%% Alloc failed\n");
238
0
    return CMD_WARNING_CONFIG_FAILED;
239
0
  }
240
0
  locator->status_up = true;
241
242
0
  VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator);
243
0
  vty->node = SRV6_LOC_NODE;
244
0
  return CMD_SUCCESS;
245
0
}
246
247
DEFUN (no_srv6_locator,
248
       no_srv6_locator_cmd,
249
       "no locator WORD",
250
       NO_STR
251
       "Segment Routing SRv6 locator\n"
252
       "Specify locator-name\n")
253
0
{
254
0
  struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg);
255
0
  if (!locator) {
256
0
    vty_out(vty, "%% Can't find SRv6 locator\n");
257
0
    return CMD_WARNING_CONFIG_FAILED;
258
0
  }
259
260
0
  zebra_srv6_locator_delete(locator);
261
0
  return CMD_SUCCESS;
262
0
}
263
264
DEFPY (locator_prefix,
265
       locator_prefix_cmd,
266
       "prefix X:X::X:X/M$prefix [block-len (16-64)$block_bit_len]  \
267
          [node-len (16-64)$node_bit_len] [func-bits (0-64)$func_bit_len]",
268
       "Configure SRv6 locator prefix\n"
269
       "Specify SRv6 locator prefix\n"
270
       "Configure SRv6 locator block length in bits\n"
271
       "Specify SRv6 locator block length in bits\n"
272
       "Configure SRv6 locator node length in bits\n"
273
       "Specify SRv6 locator node length in bits\n"
274
       "Configure SRv6 locator function length in bits\n"
275
       "Specify SRv6 locator function length in bits\n")
276
0
{
277
0
  VTY_DECLVAR_CONTEXT(srv6_locator, locator);
278
0
  struct srv6_locator_chunk *chunk = NULL;
279
0
  struct listnode *node = NULL;
280
281
0
  locator->prefix = *prefix;
282
0
  func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH;
283
284
  /* Resolve optional arguments */
285
0
  if (block_bit_len == 0 && node_bit_len == 0) {
286
0
    block_bit_len =
287
0
      prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
288
0
    node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
289
0
  } else if (block_bit_len == 0) {
290
0
    block_bit_len = prefix->prefixlen - node_bit_len;
291
0
  } else if (node_bit_len == 0) {
292
0
    node_bit_len = prefix->prefixlen - block_bit_len;
293
0
  } else {
294
0
    if (block_bit_len + node_bit_len != prefix->prefixlen) {
295
0
      vty_out(vty,
296
0
        "%% block-len + node-len must be equal to the selected prefix length %d\n",
297
0
        prefix->prefixlen);
298
0
      return CMD_WARNING_CONFIG_FAILED;
299
0
    }
300
0
  }
301
302
0
  if (prefix->prefixlen + func_bit_len + 0 > 128) {
303
0
    vty_out(vty,
304
0
      "%% prefix-len + function-len + arg-len (%ld) cannot be greater than 128\n",
305
0
      prefix->prefixlen + func_bit_len + 0);
306
0
    return CMD_WARNING_CONFIG_FAILED;
307
0
  }
308
309
  /*
310
   * Currently, the SID transposition algorithm implemented in bgpd
311
   * handles incorrectly the SRv6 locators with function length greater
312
   * than 20 bits. To prevent issues, we currently limit the function
313
   * length to 20 bits.
314
   * This limit will be removed when the bgpd SID transposition is fixed.
315
   */
316
0
  if (func_bit_len > 20) {
317
0
    vty_out(vty,
318
0
      "%% currently func_bit_len > 20 is not supported\n");
319
0
    return CMD_WARNING_CONFIG_FAILED;
320
0
  }
321
322
0
  locator->block_bits_length = block_bit_len;
323
0
  locator->node_bits_length = node_bit_len;
324
0
  locator->function_bits_length = func_bit_len;
325
0
  locator->argument_bits_length = 0;
326
327
0
  if (list_isempty(locator->chunks)) {
328
0
    chunk = srv6_locator_chunk_alloc();
329
0
    chunk->prefix = *prefix;
330
0
    chunk->proto = 0;
331
0
    listnode_add(locator->chunks, chunk);
332
0
  } else {
333
0
    for (ALL_LIST_ELEMENTS_RO(locator->chunks, node, chunk)) {
334
0
      uint8_t zero[16] = {0};
335
336
0
      if (memcmp(&chunk->prefix.prefix, zero, 16) == 0) {
337
0
        struct zserv *client;
338
0
        struct listnode *client_node;
339
340
0
        chunk->prefix = *prefix;
341
0
        for (ALL_LIST_ELEMENTS_RO(zrouter.client_list,
342
0
                client_node,
343
0
                client)) {
344
0
          struct srv6_locator *tmp;
345
346
0
          if (client->proto != chunk->proto)
347
0
            continue;
348
349
0
          srv6_manager_get_locator_chunk_call(
350
0
              &tmp, client,
351
0
              locator->name,
352
0
              VRF_DEFAULT);
353
0
        }
354
0
      }
355
0
    }
356
0
  }
357
358
0
  zebra_srv6_locator_add(locator);
359
0
  return CMD_SUCCESS;
360
0
}
361
362
DEFPY (locator_behavior,
363
       locator_behavior_cmd,
364
       "[no] behavior usid",
365
       NO_STR
366
       "Configure SRv6 behavior\n"
367
       "Specify SRv6 behavior uSID\n")
368
0
{
369
0
  VTY_DECLVAR_CONTEXT(srv6_locator, locator);
370
371
0
  if (no && !CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
372
    /* SRv6 locator uSID flag already unset, nothing to do */
373
0
    return CMD_SUCCESS;
374
375
0
  if (!no && CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
376
    /* SRv6 locator uSID flag already set, nothing to do */
377
0
    return CMD_SUCCESS;
378
379
  /* Remove old locator from zclients */
380
0
  zebra_notify_srv6_locator_delete(locator);
381
382
  /* Set/Unset the SRV6_LOCATOR_USID */
383
0
  if (no)
384
0
    UNSET_FLAG(locator->flags, SRV6_LOCATOR_USID);
385
0
  else
386
0
    SET_FLAG(locator->flags, SRV6_LOCATOR_USID);
387
388
  /* Notify the new locator to zclients */
389
0
  zebra_notify_srv6_locator_add(locator);
390
391
0
  return CMD_SUCCESS;
392
0
}
393
394
static int zebra_sr_config(struct vty *vty)
395
0
{
396
0
  struct zebra_srv6 *srv6 = zebra_srv6_get_default();
397
0
  struct listnode *node;
398
0
  struct srv6_locator *locator;
399
0
  char str[256];
400
401
0
  vty_out(vty, "!\n");
402
0
  if (zebra_srv6_is_enable()) {
403
0
    vty_out(vty, "segment-routing\n");
404
0
    vty_out(vty, " srv6\n");
405
0
    vty_out(vty, "  locators\n");
406
0
    for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
407
0
      inet_ntop(AF_INET6, &locator->prefix.prefix,
408
0
          str, sizeof(str));
409
0
      vty_out(vty, "   locator %s\n", locator->name);
410
0
      vty_out(vty, "    prefix %s/%u", str,
411
0
        locator->prefix.prefixlen);
412
0
      if (locator->block_bits_length)
413
0
        vty_out(vty, " block-len %u",
414
0
          locator->block_bits_length);
415
0
      if (locator->node_bits_length)
416
0
        vty_out(vty, " node-len %u",
417
0
          locator->node_bits_length);
418
0
      if (locator->function_bits_length)
419
0
        vty_out(vty, " func-bits %u",
420
0
          locator->function_bits_length);
421
0
      if (locator->argument_bits_length)
422
0
        vty_out(vty, " arg-len %u",
423
0
          locator->argument_bits_length);
424
0
      vty_out(vty, "\n");
425
0
      if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
426
0
        vty_out(vty, "    behavior usid\n");
427
0
      vty_out(vty, "   exit\n");
428
0
      vty_out(vty, "   !\n");
429
0
    }
430
0
    vty_out(vty, "  exit\n");
431
0
    vty_out(vty, "  !\n");
432
0
    vty_out(vty, " exit\n");
433
0
    vty_out(vty, " !\n");
434
0
    vty_out(vty, "exit\n");
435
0
    vty_out(vty, "!\n");
436
0
  }
437
0
  return 0;
438
0
}
439
440
void zebra_srv6_vty_init(void)
441
0
{
442
  /* Install nodes and its default commands */
443
0
  install_node(&sr_node);
444
0
  install_node(&srv6_node);
445
0
  install_node(&srv6_locs_node);
446
0
  install_node(&srv6_loc_node);
447
0
  install_default(SEGMENT_ROUTING_NODE);
448
0
  install_default(SRV6_NODE);
449
0
  install_default(SRV6_LOCS_NODE);
450
0
  install_default(SRV6_LOC_NODE);
451
452
  /* Command for change node */
453
0
  install_element(CONFIG_NODE, &segment_routing_cmd);
454
0
  install_element(SEGMENT_ROUTING_NODE, &srv6_cmd);
455
0
  install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd);
456
0
  install_element(SRV6_NODE, &srv6_locators_cmd);
457
0
  install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
458
0
  install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd);
459
460
  /* Command for configuration */
461
0
  install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
462
0
  install_element(SRV6_LOC_NODE, &locator_behavior_cmd);
463
464
  /* Command for operation */
465
0
  install_element(VIEW_NODE, &show_srv6_locator_cmd);
466
0
  install_element(VIEW_NODE, &show_srv6_locator_detail_cmd);
467
0
}