]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_srv6_vty.c
Merge pull request #12811 from Avineus/frr_neighlog_5884
[mirror_frr.git] / zebra / zebra_srv6_vty.c
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 {
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;
77 char str[256];
78 int id;
79 json_object *json = NULL;
80 json_object *json_locators = NULL;
81 json_object *json_locator = NULL;
82
83 if (uj) {
84 json = json_object_new_object();
85 json_locators = json_object_new_array();
86 json_object_object_add(json, "locators", json_locators);
87
88 for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
89 json_locator = srv6_locator_json(locator);
90 if (!json_locator)
91 continue;
92 json_object_array_add(json_locators, json_locator);
93
94 }
95
96 vty_json(vty, json);
97 } else {
98 vty_out(vty, "Locator:\n");
99 vty_out(vty, "Name ID Prefix Status\n");
100 vty_out(vty, "-------------------- ------- ------------------------ -------\n");
101
102 id = 1;
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");
108 ++id;
109 }
110 vty_out(vty, "\n");
111 }
112
113 return CMD_SUCCESS;
114 }
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 {
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;
131 char str[256];
132 const char *locator_name = argv[4]->arg;
133 json_object *json_locator = NULL;
134
135 if (uj) {
136 locator = zebra_srv6_locator_lookup(locator_name);
137 if (!locator)
138 return CMD_WARNING;
139
140 json_locator = srv6_locator_detailed_json(locator);
141 vty_json(vty, json_locator);
142 return CMD_SUCCESS;
143 }
144
145 for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
146 struct listnode *node;
147 struct srv6_locator_chunk *chunk;
148
149 if (strcmp(locator->name, locator_name) != 0)
150 continue;
151
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);
161
162 if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
163 vty_out(vty, "Behavior: uSID\n");
164
165 vty_out(vty, "Chunks:\n");
166 for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node,
167 chunk)) {
168 prefix2str(&chunk->prefix, str, sizeof(str));
169 vty_out(vty, "- prefix: %s, owner: %s\n", str,
170 zebra_route_string(chunk->proto));
171 }
172 }
173
174
175 return CMD_SUCCESS;
176 }
177
178 DEFUN_NOSH (segment_routing,
179 segment_routing_cmd,
180 "segment-routing",
181 "Segment Routing\n")
182 {
183 vty->node = SEGMENT_ROUTING_NODE;
184 return CMD_SUCCESS;
185 }
186
187 DEFUN_NOSH (srv6,
188 srv6_cmd,
189 "srv6",
190 "Segment Routing SRv6\n")
191 {
192 vty->node = SRV6_NODE;
193 return CMD_SUCCESS;
194 }
195
196 DEFUN (no_srv6,
197 no_srv6_cmd,
198 "no srv6",
199 NO_STR
200 "Segment Routing SRv6\n")
201 {
202 struct zebra_srv6 *srv6 = zebra_srv6_get_default();
203 struct srv6_locator *locator;
204 struct listnode *node, *nnode;
205
206 for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator))
207 zebra_srv6_locator_delete(locator);
208 return CMD_SUCCESS;
209 }
210
211 DEFUN_NOSH (srv6_locators,
212 srv6_locators_cmd,
213 "locators",
214 "Segment Routing SRv6 locators\n")
215 {
216 vty->node = SRV6_LOCS_NODE;
217 return CMD_SUCCESS;
218 }
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 {
226 struct srv6_locator *locator = NULL;
227
228 locator = zebra_srv6_locator_lookup(argv[1]->arg);
229 if (locator) {
230 VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator);
231 locator->status_up = true;
232 return CMD_SUCCESS;
233 }
234
235 locator = srv6_locator_alloc(argv[1]->arg);
236 if (!locator) {
237 vty_out(vty, "%% Alloc failed\n");
238 return CMD_WARNING_CONFIG_FAILED;
239 }
240 locator->status_up = true;
241
242 VTY_PUSH_CONTEXT(SRV6_LOC_NODE, locator);
243 vty->node = SRV6_LOC_NODE;
244 return CMD_SUCCESS;
245 }
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 {
254 struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg);
255 if (!locator) {
256 vty_out(vty, "%% Can't find SRv6 locator\n");
257 return CMD_WARNING_CONFIG_FAILED;
258 }
259
260 zebra_srv6_locator_delete(locator);
261 return CMD_SUCCESS;
262 }
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 {
277 VTY_DECLVAR_CONTEXT(srv6_locator, locator);
278 struct srv6_locator_chunk *chunk = NULL;
279 struct listnode *node = NULL;
280
281 locator->prefix = *prefix;
282 func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH;
283
284 /* Resolve optional arguments */
285 if (block_bit_len == 0 && node_bit_len == 0) {
286 block_bit_len =
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;
293 } else {
294 if (block_bit_len + node_bit_len != prefix->prefixlen) {
295 vty_out(vty,
296 "%% block-len + node-len must be equal to the selected prefix length %d\n",
297 prefix->prefixlen);
298 return CMD_WARNING_CONFIG_FAILED;
299 }
300 }
301
302 if (prefix->prefixlen + func_bit_len + 0 > 128) {
303 vty_out(vty,
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;
307 }
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 if (func_bit_len > 20) {
317 vty_out(vty,
318 "%% currently func_bit_len > 20 is not supported\n");
319 return CMD_WARNING_CONFIG_FAILED;
320 }
321
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;
326
327 if (list_isempty(locator->chunks)) {
328 chunk = srv6_locator_chunk_alloc();
329 chunk->prefix = *prefix;
330 chunk->proto = 0;
331 listnode_add(locator->chunks, chunk);
332 } else {
333 for (ALL_LIST_ELEMENTS_RO(locator->chunks, node, chunk)) {
334 uint8_t zero[16] = {0};
335
336 if (memcmp(&chunk->prefix.prefix, zero, 16) == 0) {
337 struct zserv *client;
338 struct listnode *client_node;
339
340 chunk->prefix = *prefix;
341 for (ALL_LIST_ELEMENTS_RO(zrouter.client_list,
342 client_node,
343 client)) {
344 struct srv6_locator *tmp;
345
346 if (client->proto != chunk->proto)
347 continue;
348
349 srv6_manager_get_locator_chunk_call(
350 &tmp, client,
351 locator->name,
352 VRF_DEFAULT);
353 }
354 }
355 }
356 }
357
358 zebra_srv6_locator_add(locator);
359 return CMD_SUCCESS;
360 }
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 {
369 VTY_DECLVAR_CONTEXT(srv6_locator, locator);
370
371 if (no && !CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
372 /* SRv6 locator uSID flag already unset, nothing to do */
373 return CMD_SUCCESS;
374
375 if (!no && CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
376 /* SRv6 locator uSID flag already set, nothing to do */
377 return CMD_SUCCESS;
378
379 /* Remove old locator from zclients */
380 zebra_notify_srv6_locator_delete(locator);
381
382 /* Set/Unset the SRV6_LOCATOR_USID */
383 if (no)
384 UNSET_FLAG(locator->flags, SRV6_LOCATOR_USID);
385 else
386 SET_FLAG(locator->flags, SRV6_LOCATOR_USID);
387
388 /* Notify the new locator to zclients */
389 zebra_notify_srv6_locator_add(locator);
390
391 return CMD_SUCCESS;
392 }
393
394 static int zebra_sr_config(struct vty *vty)
395 {
396 struct zebra_srv6 *srv6 = zebra_srv6_get_default();
397 struct listnode *node;
398 struct srv6_locator *locator;
399 char str[256];
400
401 vty_out(vty, "!\n");
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,
408 str, sizeof(str));
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);
424 vty_out(vty, "\n");
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");
429 }
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");
435 vty_out(vty, "!\n");
436 }
437 return 0;
438 }
439
440 void zebra_srv6_vty_init(void)
441 {
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);
451
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);
459
460 /* Command for configuration */
461 install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
462 install_element(SRV6_LOC_NODE, &locator_behavior_cmd);
463
464 /* Command for operation */
465 install_element(VIEW_NODE, &show_srv6_locator_cmd);
466 install_element(VIEW_NODE, &show_srv6_locator_detail_cmd);
467 }