1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Zebra SRv6 VTY functions
4 * Copyright (C) 2020 Hiroki Shirokura, LINE Corporation
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"
30 #include "zebra/zebra_srv6_vty_clippy.c"
32 static int zebra_sr_config(struct vty
*vty
);
34 static struct cmd_node sr_node
= {
36 .node
= SEGMENT_ROUTING_NODE
,
37 .parent_node
= CONFIG_NODE
,
38 .prompt
= "%s(config-sr)# ",
39 .config_write
= zebra_sr_config
,
42 static struct cmd_node srv6_node
= {
45 .parent_node
= SEGMENT_ROUTING_NODE
,
46 .prompt
= "%s(config-srv6)# ",
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)# ",
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)# "
64 DEFUN (show_srv6_locator
,
65 show_srv6_locator_cmd
,
66 "show segment-routing srv6 locator [json]",
69 "Segment Routing SRv6\n"
70 "Locator Information\n"
73 const bool uj
= use_json(argc
, argv
);
74 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
75 struct srv6_locator
*locator
;
76 struct listnode
*node
;
79 json_object
*json
= NULL
;
80 json_object
*json_locators
= NULL
;
81 json_object
*json_locator
= NULL
;
84 json
= json_object_new_object();
85 json_locators
= json_object_new_array();
86 json_object_object_add(json
, "locators", json_locators
);
88 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, node
, locator
)) {
89 json_locator
= srv6_locator_json(locator
);
92 json_object_array_add(json_locators
, json_locator
);
98 vty_out(vty
, "Locator:\n");
99 vty_out(vty
, "Name ID Prefix Status\n");
100 vty_out(vty
, "-------------------- ------- ------------------------ -------\n");
103 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, node
, locator
)) {
104 prefix2str(&locator
->prefix
, str
, sizeof(str
));
105 vty_out(vty
, "%-20s %7d %-24s %s\n",
106 locator
->name
, id
, str
,
107 locator
->status_up
? "Up" : "Down");
116 DEFUN (show_srv6_locator_detail
,
117 show_srv6_locator_detail_cmd
,
118 "show segment-routing srv6 locator NAME detail [json]",
121 "Segment Routing SRv6\n"
122 "Locator Information\n"
124 "Detailed information\n"
127 const bool uj
= use_json(argc
, argv
);
128 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
129 struct srv6_locator
*locator
;
130 struct listnode
*node
;
132 const char *locator_name
= argv
[4]->arg
;
133 json_object
*json_locator
= NULL
;
136 locator
= zebra_srv6_locator_lookup(locator_name
);
140 json_locator
= srv6_locator_detailed_json(locator
);
141 vty_json(vty
, json_locator
);
145 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, node
, locator
)) {
146 struct listnode
*node
;
147 struct srv6_locator_chunk
*chunk
;
149 if (strcmp(locator
->name
, locator_name
) != 0)
152 prefix2str(&locator
->prefix
, str
, sizeof(str
));
153 vty_out(vty
, "Name: %s\n", locator
->name
);
154 vty_out(vty
, "Prefix: %s\n", str
);
155 vty_out(vty
, "Block-Bit-Len: %u\n", locator
->block_bits_length
);
156 vty_out(vty
, "Node-Bit-Len: %u\n", locator
->node_bits_length
);
157 vty_out(vty
, "Function-Bit-Len: %u\n",
158 locator
->function_bits_length
);
159 vty_out(vty
, "Argument-Bit-Len: %u\n",
160 locator
->argument_bits_length
);
162 if (CHECK_FLAG(locator
->flags
, SRV6_LOCATOR_USID
))
163 vty_out(vty
, "Behavior: uSID\n");
165 vty_out(vty
, "Chunks:\n");
166 for (ALL_LIST_ELEMENTS_RO((struct list
*)locator
->chunks
, node
,
168 prefix2str(&chunk
->prefix
, str
, sizeof(str
));
169 vty_out(vty
, "- prefix: %s, owner: %s\n", str
,
170 zebra_route_string(chunk
->proto
));
178 DEFUN_NOSH (segment_routing
,
183 vty
->node
= SEGMENT_ROUTING_NODE
;
190 "Segment Routing SRv6\n")
192 vty
->node
= SRV6_NODE
;
200 "Segment Routing SRv6\n")
202 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
203 struct srv6_locator
*locator
;
204 struct listnode
*node
, *nnode
;
206 for (ALL_LIST_ELEMENTS(srv6
->locators
, node
, nnode
, locator
))
207 zebra_srv6_locator_delete(locator
);
211 DEFUN_NOSH (srv6_locators
,
214 "Segment Routing SRv6 locators\n")
216 vty
->node
= SRV6_LOCS_NODE
;
220 DEFUN_NOSH (srv6_locator
,
223 "Segment Routing SRv6 locator\n"
224 "Specify locator-name\n")
226 struct srv6_locator
*locator
= NULL
;
228 locator
= zebra_srv6_locator_lookup(argv
[1]->arg
);
230 VTY_PUSH_CONTEXT(SRV6_LOC_NODE
, locator
);
231 locator
->status_up
= true;
235 locator
= srv6_locator_alloc(argv
[1]->arg
);
237 vty_out(vty
, "%% Alloc failed\n");
238 return CMD_WARNING_CONFIG_FAILED
;
240 locator
->status_up
= true;
242 VTY_PUSH_CONTEXT(SRV6_LOC_NODE
, locator
);
243 vty
->node
= SRV6_LOC_NODE
;
247 DEFUN (no_srv6_locator
,
251 "Segment Routing SRv6 locator\n"
252 "Specify locator-name\n")
254 struct srv6_locator
*locator
= zebra_srv6_locator_lookup(argv
[2]->arg
);
256 vty_out(vty
, "%% Can't find SRv6 locator\n");
257 return CMD_WARNING_CONFIG_FAILED
;
260 zebra_srv6_locator_delete(locator
);
264 DEFPY (locator_prefix
,
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")
277 VTY_DECLVAR_CONTEXT(srv6_locator
, locator
);
278 struct srv6_locator_chunk
*chunk
= NULL
;
279 struct listnode
*node
= NULL
;
281 locator
->prefix
= *prefix
;
282 func_bit_len
= func_bit_len
?: ZEBRA_SRV6_FUNCTION_LENGTH
;
284 /* Resolve optional arguments */
285 if (block_bit_len
== 0 && node_bit_len
== 0) {
287 prefix
->prefixlen
- ZEBRA_SRV6_LOCATOR_NODE_LENGTH
;
288 node_bit_len
= ZEBRA_SRV6_LOCATOR_NODE_LENGTH
;
289 } else if (block_bit_len
== 0) {
290 block_bit_len
= prefix
->prefixlen
- node_bit_len
;
291 } else if (node_bit_len
== 0) {
292 node_bit_len
= prefix
->prefixlen
- block_bit_len
;
294 if (block_bit_len
+ node_bit_len
!= prefix
->prefixlen
) {
296 "%% block-len + node-len must be equal to the selected prefix length %d\n",
298 return CMD_WARNING_CONFIG_FAILED
;
302 if (prefix
->prefixlen
+ func_bit_len
+ 0 > 128) {
304 "%% prefix-len + function-len + arg-len (%ld) cannot be greater than 128\n",
305 prefix
->prefixlen
+ func_bit_len
+ 0);
306 return CMD_WARNING_CONFIG_FAILED
;
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
314 * This limit will be removed when the bgpd SID transposition is fixed.
316 if (func_bit_len
> 20) {
318 "%% currently func_bit_len > 20 is not supported\n");
319 return CMD_WARNING_CONFIG_FAILED
;
322 locator
->block_bits_length
= block_bit_len
;
323 locator
->node_bits_length
= node_bit_len
;
324 locator
->function_bits_length
= func_bit_len
;
325 locator
->argument_bits_length
= 0;
327 if (list_isempty(locator
->chunks
)) {
328 chunk
= srv6_locator_chunk_alloc();
329 chunk
->prefix
= *prefix
;
331 listnode_add(locator
->chunks
, chunk
);
333 for (ALL_LIST_ELEMENTS_RO(locator
->chunks
, node
, chunk
)) {
334 uint8_t zero
[16] = {0};
336 if (memcmp(&chunk
->prefix
.prefix
, zero
, 16) == 0) {
337 struct zserv
*client
;
338 struct listnode
*client_node
;
340 chunk
->prefix
= *prefix
;
341 for (ALL_LIST_ELEMENTS_RO(zrouter
.client_list
,
344 struct srv6_locator
*tmp
;
346 if (client
->proto
!= chunk
->proto
)
349 srv6_manager_get_locator_chunk_call(
358 zebra_srv6_locator_add(locator
);
362 DEFPY (locator_behavior
,
363 locator_behavior_cmd
,
364 "[no] behavior usid",
366 "Configure SRv6 behavior\n"
367 "Specify SRv6 behavior uSID\n")
369 VTY_DECLVAR_CONTEXT(srv6_locator
, locator
);
371 if (no
&& !CHECK_FLAG(locator
->flags
, SRV6_LOCATOR_USID
))
372 /* SRv6 locator uSID flag already unset, nothing to do */
375 if (!no
&& CHECK_FLAG(locator
->flags
, SRV6_LOCATOR_USID
))
376 /* SRv6 locator uSID flag already set, nothing to do */
379 /* Remove old locator from zclients */
380 zebra_notify_srv6_locator_delete(locator
);
382 /* Set/Unset the SRV6_LOCATOR_USID */
384 UNSET_FLAG(locator
->flags
, SRV6_LOCATOR_USID
);
386 SET_FLAG(locator
->flags
, SRV6_LOCATOR_USID
);
388 /* Notify the new locator to zclients */
389 zebra_notify_srv6_locator_add(locator
);
394 static int zebra_sr_config(struct vty
*vty
)
396 struct zebra_srv6
*srv6
= zebra_srv6_get_default();
397 struct listnode
*node
;
398 struct srv6_locator
*locator
;
402 if (zebra_srv6_is_enable()) {
403 vty_out(vty
, "segment-routing\n");
404 vty_out(vty
, " srv6\n");
405 vty_out(vty
, " locators\n");
406 for (ALL_LIST_ELEMENTS_RO(srv6
->locators
, node
, locator
)) {
407 inet_ntop(AF_INET6
, &locator
->prefix
.prefix
,
409 vty_out(vty
, " locator %s\n", locator
->name
);
410 vty_out(vty
, " prefix %s/%u", str
,
411 locator
->prefix
.prefixlen
);
412 if (locator
->block_bits_length
)
413 vty_out(vty
, " block-len %u",
414 locator
->block_bits_length
);
415 if (locator
->node_bits_length
)
416 vty_out(vty
, " node-len %u",
417 locator
->node_bits_length
);
418 if (locator
->function_bits_length
)
419 vty_out(vty
, " func-bits %u",
420 locator
->function_bits_length
);
421 if (locator
->argument_bits_length
)
422 vty_out(vty
, " arg-len %u",
423 locator
->argument_bits_length
);
425 if (CHECK_FLAG(locator
->flags
, SRV6_LOCATOR_USID
))
426 vty_out(vty
, " behavior usid\n");
427 vty_out(vty
, " exit\n");
428 vty_out(vty
, " !\n");
430 vty_out(vty
, " exit\n");
431 vty_out(vty
, " !\n");
432 vty_out(vty
, " exit\n");
433 vty_out(vty
, " !\n");
434 vty_out(vty
, "exit\n");
440 void zebra_srv6_vty_init(void)
442 /* Install nodes and its default commands */
443 install_node(&sr_node
);
444 install_node(&srv6_node
);
445 install_node(&srv6_locs_node
);
446 install_node(&srv6_loc_node
);
447 install_default(SEGMENT_ROUTING_NODE
);
448 install_default(SRV6_NODE
);
449 install_default(SRV6_LOCS_NODE
);
450 install_default(SRV6_LOC_NODE
);
452 /* Command for change node */
453 install_element(CONFIG_NODE
, &segment_routing_cmd
);
454 install_element(SEGMENT_ROUTING_NODE
, &srv6_cmd
);
455 install_element(SEGMENT_ROUTING_NODE
, &no_srv6_cmd
);
456 install_element(SRV6_NODE
, &srv6_locators_cmd
);
457 install_element(SRV6_LOCS_NODE
, &srv6_locator_cmd
);
458 install_element(SRV6_LOCS_NODE
, &no_srv6_locator_cmd
);
460 /* Command for configuration */
461 install_element(SRV6_LOC_NODE
, &locator_prefix_cmd
);
462 install_element(SRV6_LOC_NODE
, &locator_behavior_cmd
);
464 /* Command for operation */
465 install_element(VIEW_NODE
, &show_srv6_locator_cmd
);
466 install_element(VIEW_NODE
, &show_srv6_locator_detail_cmd
);