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