]> git.proxmox.com Git - mirror_frr.git/blob - sharpd/sharp_vty.c
bgpd: Expand 'bgp default <afi>-<safi>' cmds
[mirror_frr.git] / sharpd / sharp_vty.c
1 /*
2 * SHARP - vty code
3 * Copyright (C) Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #include <zebra.h>
23
24 #include "vty.h"
25 #include "command.h"
26 #include "prefix.h"
27 #include "nexthop.h"
28 #include "log.h"
29 #include "vrf.h"
30 #include "zclient.h"
31 #include "nexthop_group.h"
32 #include "link_state.h"
33
34 #include "sharpd/sharp_globals.h"
35 #include "sharpd/sharp_zebra.h"
36 #include "sharpd/sharp_nht.h"
37 #include "sharpd/sharp_vty.h"
38 #ifndef VTYSH_EXTRACT_PL
39 #include "sharpd/sharp_vty_clippy.c"
40 #endif
41
42 DEFINE_MTYPE_STATIC(SHARPD, SRV6_LOCATOR, "SRv6 Locator");
43
44 DEFPY(watch_redistribute, watch_redistribute_cmd,
45 "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD,
46 "Sharp routing Protocol\n"
47 "Watch for changes\n"
48 "The vrf we would like to watch if non-default\n"
49 "The NAME of the vrf\n"
50 "Redistribute into Sharp\n"
51 FRR_REDIST_HELP_STR_SHARPD)
52 {
53 struct vrf *vrf;
54 int source;
55
56 if (!vrf_name)
57 vrf_name = VRF_DEFAULT_NAME;
58 vrf = vrf_lookup_by_name(vrf_name);
59 if (!vrf) {
60 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
61 vrf_name);
62 return CMD_WARNING;
63 }
64
65 source = proto_redistnum(AFI_IP, argv[argc-1]->text);
66 sharp_redistribute_vrf(vrf, source);
67
68 return CMD_SUCCESS;
69 }
70
71 DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
72 "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
73 "Sharp routing Protocol\n"
74 "Watch for changes\n"
75 "The vrf we would like to watch if non-default\n"
76 "The NAME of the vrf\n"
77 "Watch for nexthop changes\n"
78 "The v6 nexthop to signal for watching\n"
79 "Watch for import check changes\n"
80 "The v6 prefix to signal for watching\n"
81 "Should the route be connected\n")
82 {
83 struct vrf *vrf;
84 struct prefix p;
85 bool type_import;
86
87 if (!vrf_name)
88 vrf_name = VRF_DEFAULT_NAME;
89 vrf = vrf_lookup_by_name(vrf_name);
90 if (!vrf) {
91 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
92 vrf_name);
93 return CMD_WARNING;
94 }
95
96 memset(&p, 0, sizeof(p));
97
98 if (n) {
99 type_import = false;
100 p.prefixlen = 128;
101 memcpy(&p.u.prefix6, &nhop, 16);
102 p.family = AF_INET6;
103 } else {
104 type_import = true;
105 p = *(const struct prefix *)inhop;
106 }
107
108 sharp_nh_tracker_get(&p);
109 sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
110 true, !!connected);
111
112 return CMD_SUCCESS;
113 }
114
115 DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
116 "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
117 "Sharp routing Protocol\n"
118 "Watch for changes\n"
119 "The vrf we would like to watch if non-default\n"
120 "The NAME of the vrf\n"
121 "Watch for nexthop changes\n"
122 "The v4 address to signal for watching\n"
123 "Watch for import check changes\n"
124 "The v4 prefix for import check to watch\n"
125 "Should the route be connected\n")
126 {
127 struct vrf *vrf;
128 struct prefix p;
129 bool type_import;
130
131 if (!vrf_name)
132 vrf_name = VRF_DEFAULT_NAME;
133 vrf = vrf_lookup_by_name(vrf_name);
134 if (!vrf) {
135 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
136 vrf_name);
137 return CMD_WARNING;
138 }
139
140 memset(&p, 0, sizeof(p));
141
142 if (n) {
143 type_import = false;
144 p.prefixlen = 32;
145 p.u.prefix4 = nhop;
146 p.family = AF_INET;
147 }
148 else {
149 type_import = true;
150 p = *(const struct prefix *)inhop;
151 }
152
153 sharp_nh_tracker_get(&p);
154 sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
155 true, !!connected);
156
157 return CMD_SUCCESS;
158 }
159
160 DEFPY(sharp_nht_data_dump,
161 sharp_nht_data_dump_cmd,
162 "sharp data nexthop",
163 "Sharp routing Protocol\n"
164 "Data about what is going on\n"
165 "Nexthop information\n")
166 {
167 sharp_nh_tracker_dump(vty);
168
169 return CMD_SUCCESS;
170 }
171
172 DEFPY (install_routes_data_dump,
173 install_routes_data_dump_cmd,
174 "sharp data route",
175 "Sharp routing Protocol\n"
176 "Data about what is going on\n"
177 "Route Install/Removal Information\n")
178 {
179 struct timeval r;
180
181 timersub(&sg.r.t_end, &sg.r.t_start, &r);
182 vty_out(vty, "Prefix: %pFX Total: %u %u %u Time: %jd.%ld\n",
183 &sg.r.orig_prefix, sg.r.total_routes, sg.r.installed_routes,
184 sg.r.removed_routes, (intmax_t)r.tv_sec, (long)r.tv_usec);
185
186 return CMD_SUCCESS;
187 }
188
189 DEFPY (install_routes,
190 install_routes_cmd,
191 "sharp install routes [vrf NAME$vrf_name]\
192 <A.B.C.D$start4|X:X::X:X$start6>\
193 <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
194 nexthop-group NHGNAME$nexthop_group>\
195 [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
196 (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]",
197 "Sharp routing Protocol\n"
198 "install some routes\n"
199 "Routes to install\n"
200 "The vrf we would like to install into if non-default\n"
201 "The NAME of the vrf\n"
202 "v4 Address to start /32 generation at\n"
203 "v6 Address to start /32 generation at\n"
204 "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
205 "V4 Nexthop address to use\n"
206 "V6 Nexthop address to use\n"
207 "Nexthop-Group to use\n"
208 "The Name of the nexthop-group\n"
209 "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
210 "Backup V4 Nexthop address to use\n"
211 "Backup V6 Nexthop address to use\n"
212 "How many to create\n"
213 "Instance to use\n"
214 "Instance\n"
215 "Should we repeat this command\n"
216 "How many times to repeat this command\n"
217 "What opaque data to send down\n"
218 "The opaque data\n")
219 {
220 struct vrf *vrf;
221 struct prefix prefix;
222 uint32_t rts;
223 uint32_t nhgid = 0;
224
225 sg.r.total_routes = routes;
226 sg.r.installed_routes = 0;
227
228 if (rpt >= 2)
229 sg.r.repeat = rpt * 2;
230 else
231 sg.r.repeat = 0;
232
233 memset(&prefix, 0, sizeof(prefix));
234 memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
235 memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
236 memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
237 memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
238 memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
239
240 if (start4.s_addr != INADDR_ANY) {
241 prefix.family = AF_INET;
242 prefix.prefixlen = 32;
243 prefix.u.prefix4 = start4;
244 } else {
245 prefix.family = AF_INET6;
246 prefix.prefixlen = 128;
247 prefix.u.prefix6 = start6;
248 }
249 sg.r.orig_prefix = prefix;
250
251 if (!vrf_name)
252 vrf_name = VRF_DEFAULT_NAME;
253
254 vrf = vrf_lookup_by_name(vrf_name);
255 if (!vrf) {
256 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
257 vrf_name);
258 return CMD_WARNING;
259 }
260
261 /* Explicit backup not available with named nexthop-group */
262 if (backup && nexthop_group) {
263 vty_out(vty, "%% Invalid: cannot specify both nexthop-group and backup\n");
264 return CMD_WARNING;
265 }
266
267 if (nexthop_group) {
268 struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
269 if (!nhgc) {
270 vty_out(vty,
271 "Specified Nexthop Group: %s does not exist\n",
272 nexthop_group);
273 return CMD_WARNING;
274 }
275
276 nhgid = sharp_nhgroup_get_id(nexthop_group);
277 sg.r.nhgid = nhgid;
278 sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
279
280 /* Use group's backup nexthop info if present */
281 if (nhgc->backup_list_name[0]) {
282 struct nexthop_group_cmd *bnhgc =
283 nhgc_find(nhgc->backup_list_name);
284
285 if (!bnhgc) {
286 vty_out(vty, "%% Backup group %s not found for group %s\n",
287 nhgc->backup_list_name,
288 nhgc->name);
289 return CMD_WARNING;
290 }
291
292 sg.r.backup_nhop.vrf_id = vrf->vrf_id;
293 sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop;
294 }
295 } else {
296 if (nexthop4.s_addr != INADDR_ANY) {
297 sg.r.nhop.gate.ipv4 = nexthop4;
298 sg.r.nhop.type = NEXTHOP_TYPE_IPV4;
299 } else {
300 sg.r.nhop.gate.ipv6 = nexthop6;
301 sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
302 }
303
304 sg.r.nhop.vrf_id = vrf->vrf_id;
305 sg.r.nhop_group.nexthop = &sg.r.nhop;
306 }
307
308 /* Use single backup nexthop if specified */
309 if (backup) {
310 /* Set flag and index in primary nexthop */
311 SET_FLAG(sg.r.nhop.flags, NEXTHOP_FLAG_HAS_BACKUP);
312 sg.r.nhop.backup_num = 1;
313 sg.r.nhop.backup_idx[0] = 0;
314
315 if (backup_nexthop4.s_addr != INADDR_ANY) {
316 sg.r.backup_nhop.gate.ipv4 = backup_nexthop4;
317 sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV4;
318 } else {
319 sg.r.backup_nhop.gate.ipv6 = backup_nexthop6;
320 sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV6;
321 }
322
323 sg.r.backup_nhop.vrf_id = vrf->vrf_id;
324 sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop;
325 }
326
327 if (opaque)
328 strlcpy(sg.r.opaque, opaque, ZAPI_MESSAGE_OPAQUE_LENGTH);
329 else
330 sg.r.opaque[0] = '\0';
331
332 sg.r.inst = instance;
333 sg.r.vrf_id = vrf->vrf_id;
334 rts = routes;
335 sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid,
336 &sg.r.nhop_group, &sg.r.backup_nhop_group,
337 rts, 0, sg.r.opaque);
338
339 return CMD_SUCCESS;
340 }
341
342 DEFPY (install_seg6_routes,
343 install_seg6_routes_cmd,
344 "sharp install seg6-routes [vrf NAME$vrf_name]\
345 <A.B.C.D$start4|X:X::X:X$start6>\
346 nexthop-seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg\
347 (1-1000000)$routes [repeat (2-1000)$rpt]",
348 "Sharp routing Protocol\n"
349 "install some routes\n"
350 "Routes to install\n"
351 "The vrf we would like to install into if non-default\n"
352 "The NAME of the vrf\n"
353 "v4 Address to start /32 generation at\n"
354 "v6 Address to start /32 generation at\n"
355 "Nexthop-seg6 to use\n"
356 "V6 Nexthop address to use\n"
357 "Encap mode\n"
358 "Segment List to use\n"
359 "How many to create\n"
360 "Should we repeat this command\n"
361 "How many times to repeat this command\n")
362 {
363 struct vrf *vrf;
364 struct prefix prefix;
365 uint32_t route_flags = 0;
366
367 sg.r.total_routes = routes;
368 sg.r.installed_routes = 0;
369
370 if (rpt >= 2)
371 sg.r.repeat = rpt * 2;
372 else
373 sg.r.repeat = 0;
374
375 memset(&prefix, 0, sizeof(prefix));
376 memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
377 memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
378 memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
379 memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
380 memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
381 sg.r.opaque[0] = '\0';
382 sg.r.inst = 0;
383
384 if (start4.s_addr != INADDR_ANY) {
385 prefix.family = AF_INET;
386 prefix.prefixlen = 32;
387 prefix.u.prefix4 = start4;
388 } else {
389 prefix.family = AF_INET6;
390 prefix.prefixlen = 128;
391 prefix.u.prefix6 = start6;
392 }
393 sg.r.orig_prefix = prefix;
394
395 if (!vrf_name)
396 vrf_name = VRF_DEFAULT_NAME;
397
398 vrf = vrf_lookup_by_name(vrf_name);
399 if (!vrf) {
400 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
401 vrf_name);
402 return CMD_WARNING;
403 }
404
405 sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
406 sg.r.nhop.gate.ipv6 = seg6_nh6;
407 sg.r.nhop.vrf_id = vrf->vrf_id;
408 sg.r.nhop_group.nexthop = &sg.r.nhop;
409 nexthop_add_srv6_seg6(&sg.r.nhop, &seg6_seg);
410
411 sg.r.vrf_id = vrf->vrf_id;
412 sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, 0,
413 &sg.r.nhop_group, &sg.r.backup_nhop_group,
414 routes, route_flags, sg.r.opaque);
415
416 return CMD_SUCCESS;
417 }
418
419 DEFPY (install_seg6local_routes,
420 install_seg6local_routes_cmd,
421 "sharp install seg6local-routes [vrf NAME$vrf_name]\
422 X:X::X:X$start6\
423 nexthop-seg6local NAME$seg6l_oif\
424 <End$seg6l_end|\
425 End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
426 End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
427 End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
428 End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table>\
429 (1-1000000)$routes [repeat (2-1000)$rpt]",
430 "Sharp routing Protocol\n"
431 "install some routes\n"
432 "Routes to install\n"
433 "The vrf we would like to install into if non-default\n"
434 "The NAME of the vrf\n"
435 "v6 Address to start /32 generation at\n"
436 "Nexthop-seg6local to use\n"
437 "Output device to use\n"
438 "SRv6 End function to use\n"
439 "SRv6 End.X function to use\n"
440 "V6 Nexthop address to use\n"
441 "SRv6 End.T function to use\n"
442 "Redirect table id to use\n"
443 "SRv6 End.DX4 function to use\n"
444 "V4 Nexthop address to use\n"
445 "SRv6 End.DT6 function to use\n"
446 "Redirect table id to use\n"
447 "How many to create\n"
448 "Should we repeat this command\n"
449 "How many times to repeat this command\n")
450 {
451 struct vrf *vrf;
452 uint32_t route_flags = 0;
453 struct seg6local_context ctx = {};
454 enum seg6local_action_t action;
455
456 sg.r.total_routes = routes;
457 sg.r.installed_routes = 0;
458
459 if (rpt >= 2)
460 sg.r.repeat = rpt * 2;
461 else
462 sg.r.repeat = 0;
463
464 memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
465 memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
466 memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
467 memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
468 memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
469 sg.r.opaque[0] = '\0';
470 sg.r.inst = 0;
471 sg.r.orig_prefix.family = AF_INET6;
472 sg.r.orig_prefix.prefixlen = 128;
473 sg.r.orig_prefix.u.prefix6 = start6;
474
475 if (!vrf_name)
476 vrf_name = VRF_DEFAULT_NAME;
477
478 vrf = vrf_lookup_by_name(vrf_name);
479 if (!vrf) {
480 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
481 vrf_name);
482 return CMD_WARNING;
483 }
484
485 if (seg6l_enddx4) {
486 action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4;
487 ctx.nh4 = seg6l_enddx4_nh4;
488 } else if (seg6l_endx) {
489 action = ZEBRA_SEG6_LOCAL_ACTION_END_X;
490 ctx.nh6 = seg6l_endx_nh6;
491 } else if (seg6l_endt) {
492 action = ZEBRA_SEG6_LOCAL_ACTION_END_T;
493 ctx.table = seg6l_endt_table;
494 } else if (seg6l_enddt6) {
495 action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
496 ctx.table = seg6l_enddt6_table;
497 } else {
498 action = ZEBRA_SEG6_LOCAL_ACTION_END;
499 }
500
501 sg.r.nhop.type = NEXTHOP_TYPE_IFINDEX;
502 sg.r.nhop.ifindex = ifname2ifindex(seg6l_oif, vrf->vrf_id);
503 sg.r.nhop.vrf_id = vrf->vrf_id;
504 sg.r.nhop_group.nexthop = &sg.r.nhop;
505 nexthop_add_srv6_seg6local(&sg.r.nhop, action, &ctx);
506
507 sg.r.vrf_id = vrf->vrf_id;
508 sharp_install_routes_helper(&sg.r.orig_prefix, sg.r.vrf_id, sg.r.inst,
509 0, &sg.r.nhop_group,
510 &sg.r.backup_nhop_group, routes,
511 route_flags, sg.r.opaque);
512
513 return CMD_SUCCESS;
514 }
515
516 DEFPY(vrf_label, vrf_label_cmd,
517 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
518 "Sharp Routing Protocol\n"
519 "Give a vrf a label\n"
520 "Pop and forward for IPv4\n"
521 "Pop and forward for IPv6\n"
522 VRF_CMD_HELP_STR
523 "The label to use, 0 specifies remove the label installed from previous\n"
524 "Specified range to use\n")
525 {
526 struct vrf *vrf;
527 afi_t afi = (ipv4) ? AFI_IP : AFI_IP6;
528
529 if (strcmp(vrf_name, "default") == 0)
530 vrf = vrf_lookup_by_id(VRF_DEFAULT);
531 else
532 vrf = vrf_lookup_by_name(vrf_name);
533
534 if (!vrf) {
535 vty_out(vty, "Unable to find vrf you silly head");
536 return CMD_WARNING_CONFIG_FAILED;
537 }
538
539 if (label == 0)
540 label = MPLS_LABEL_NONE;
541
542 vrf_label_add(vrf->vrf_id, afi, label);
543 return CMD_SUCCESS;
544 }
545
546 DEFPY (remove_routes,
547 remove_routes_cmd,
548 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
549 "Sharp Routing Protocol\n"
550 "Remove some routes\n"
551 "Routes to remove\n"
552 "The vrf we would like to remove from if non-default\n"
553 "The NAME of the vrf\n"
554 "v4 Starting spot\n"
555 "v6 Starting spot\n"
556 "Routes to uninstall\n"
557 "instance to use\n"
558 "Value of instance\n")
559 {
560 struct vrf *vrf;
561 struct prefix prefix;
562
563 sg.r.total_routes = routes;
564 sg.r.removed_routes = 0;
565 uint32_t rts;
566
567 memset(&prefix, 0, sizeof(prefix));
568
569 if (start4.s_addr != INADDR_ANY) {
570 prefix.family = AF_INET;
571 prefix.prefixlen = 32;
572 prefix.u.prefix4 = start4;
573 } else {
574 prefix.family = AF_INET6;
575 prefix.prefixlen = 128;
576 prefix.u.prefix6 = start6;
577 }
578
579 vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME);
580 if (!vrf) {
581 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
582 vrf_name ? vrf_name : VRF_DEFAULT_NAME);
583 return CMD_WARNING;
584 }
585
586 sg.r.inst = instance;
587 sg.r.vrf_id = vrf->vrf_id;
588 rts = routes;
589 sharp_remove_routes_helper(&prefix, sg.r.vrf_id,
590 sg.r.inst, rts);
591
592 return CMD_SUCCESS;
593 }
594
595 DEFUN_NOSH (show_debugging_sharpd,
596 show_debugging_sharpd_cmd,
597 "show debugging [sharp]",
598 SHOW_STR
599 DEBUG_STR
600 "Sharp Information\n")
601 {
602 vty_out(vty, "Sharp debugging status:\n");
603
604 return CMD_SUCCESS;
605 }
606
607 DEFPY (sharp_lsp_prefix_v4, sharp_lsp_prefix_v4_cmd,
608 "sharp lsp [update]$update (0-100000)$inlabel\
609 nexthop-group NHGNAME$nhgname\
610 [prefix A.B.C.D/M$pfx\
611 " FRR_IP_REDIST_STR_ZEBRA "$type_str [instance (0-255)$instance]]",
612 "Sharp Routing Protocol\n"
613 "Add an LSP\n"
614 "Update an LSP\n"
615 "The ingress label to use\n"
616 "Use nexthops from a nexthop-group\n"
617 "The nexthop-group name\n"
618 "Label a prefix\n"
619 "The v4 prefix to label\n"
620 FRR_IP_REDIST_HELP_STR_ZEBRA
621 "Instance to use\n"
622 "Instance\n")
623 {
624 struct nexthop_group_cmd *nhgc = NULL;
625 struct nexthop_group_cmd *backup_nhgc = NULL;
626 struct nexthop_group *backup_nhg = NULL;
627 struct prefix p = {};
628 int type = 0;
629 bool update_p;
630
631 update_p = (update != NULL);
632
633 /* We're offered a v4 prefix */
634 if (pfx->family > 0 && type_str) {
635 p.family = pfx->family;
636 p.prefixlen = pfx->prefixlen;
637 p.u.prefix4 = pfx->prefix;
638
639 type = proto_redistnum(AFI_IP, type_str);
640 if (type < 0) {
641 vty_out(vty, "%% Unknown route type '%s'\n", type_str);
642 return CMD_WARNING;
643 }
644 } else if (pfx->family > 0 || type_str) {
645 vty_out(vty, "%% Must supply both prefix and type\n");
646 return CMD_WARNING;
647 }
648
649 nhgc = nhgc_find(nhgname);
650 if (!nhgc) {
651 vty_out(vty, "%% Nexthop-group '%s' does not exist\n",
652 nhgname);
653 return CMD_WARNING;
654 }
655
656 if (nhgc->nhg.nexthop == NULL) {
657 vty_out(vty, "%% Nexthop-group '%s' is empty\n", nhgname);
658 return CMD_WARNING;
659 }
660
661 /* Use group's backup nexthop info if present */
662 if (nhgc->backup_list_name[0]) {
663 backup_nhgc = nhgc_find(nhgc->backup_list_name);
664
665 if (!backup_nhgc) {
666 vty_out(vty,
667 "%% Backup group %s not found for group %s\n",
668 nhgc->backup_list_name,
669 nhgname);
670 return CMD_WARNING;
671 }
672 backup_nhg = &(backup_nhgc->nhg);
673 }
674
675 if (sharp_install_lsps_helper(true /*install*/, update_p,
676 pfx->family > 0 ? &p : NULL,
677 type, instance, inlabel,
678 &(nhgc->nhg), backup_nhg) == 0)
679 return CMD_SUCCESS;
680 else {
681 vty_out(vty, "%% LSP install failed!\n");
682 return CMD_WARNING;
683 }
684 }
685
686 DEFPY(sharp_remove_lsp_prefix_v4, sharp_remove_lsp_prefix_v4_cmd,
687 "sharp remove lsp \
688 (0-100000)$inlabel\
689 [nexthop-group NHGNAME$nhgname] \
690 [prefix A.B.C.D/M$pfx\
691 " FRR_IP_REDIST_STR_ZEBRA "$type_str [instance (0-255)$instance]]",
692 "Sharp Routing Protocol\n"
693 "Remove data\n"
694 "Remove an LSP\n"
695 "The ingress label\n"
696 "Use nexthops from a nexthop-group\n"
697 "The nexthop-group name\n"
698 "Specify a v4 prefix\n"
699 "The v4 prefix to label\n"
700 FRR_IP_REDIST_HELP_STR_ZEBRA
701 "Routing instance\n"
702 "Instance to use\n")
703 {
704 struct nexthop_group_cmd *nhgc = NULL;
705 struct prefix p = {};
706 int type = 0;
707 struct nexthop_group *nhg = NULL;
708
709 /* We're offered a v4 prefix */
710 if (pfx->family > 0 && type_str) {
711 p.family = pfx->family;
712 p.prefixlen = pfx->prefixlen;
713 p.u.prefix4 = pfx->prefix;
714
715 type = proto_redistnum(AFI_IP, type_str);
716 if (type < 0) {
717 vty_out(vty, "%% Unknown route type '%s'\n", type_str);
718 return CMD_WARNING;
719 }
720 } else if (pfx->family > 0 || type_str) {
721 vty_out(vty, "%% Must supply both prefix and type\n");
722 return CMD_WARNING;
723 }
724
725 if (nhgname) {
726 nhgc = nhgc_find(nhgname);
727 if (!nhgc) {
728 vty_out(vty, "%% Nexthop-group '%s' does not exist\n",
729 nhgname);
730 return CMD_WARNING;
731 }
732
733 if (nhgc->nhg.nexthop == NULL) {
734 vty_out(vty, "%% Nexthop-group '%s' is empty\n",
735 nhgname);
736 return CMD_WARNING;
737 }
738 nhg = &(nhgc->nhg);
739 }
740
741 if (sharp_install_lsps_helper(false /*!install*/, false,
742 pfx->family > 0 ? &p : NULL,
743 type, instance, inlabel, nhg, NULL) == 0)
744 return CMD_SUCCESS;
745 else {
746 vty_out(vty, "%% LSP remove failed!\n");
747 return CMD_WARNING;
748 }
749 }
750
751 DEFPY (logpump,
752 logpump_cmd,
753 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
754 "Sharp Routing Protocol\n"
755 "Generate bulk log messages for testing\n"
756 "Duration of run (s)\n"
757 "Duration of run (s)\n"
758 "Frequency of bursts (s^-1)\n"
759 "Frequency of bursts (s^-1)\n"
760 "Number of log messages per each burst\n"
761 "Number of log messages per each burst\n")
762 {
763 sharp_logpump_run(vty, duration, frequency, burst);
764 return CMD_SUCCESS;
765 }
766
767 DEFPY (create_session,
768 create_session_cmd,
769 "sharp create session (1-1024)",
770 "Sharp Routing Protocol\n"
771 "Create data\n"
772 "Create a test session\n"
773 "Session ID\n")
774 {
775 if (sharp_zclient_create(session) != 0) {
776 vty_out(vty, "%% Client session error\n");
777 return CMD_WARNING;
778 }
779
780 return CMD_SUCCESS;
781 }
782
783 DEFPY (remove_session,
784 remove_session_cmd,
785 "sharp remove session (1-1024)",
786 "Sharp Routing Protocol\n"
787 "Remove data\n"
788 "Remove a test session\n"
789 "Session ID\n")
790 {
791 sharp_zclient_delete(session);
792 return CMD_SUCCESS;
793 }
794
795 DEFPY (send_opaque,
796 send_opaque_cmd,
797 "sharp send opaque type (1-255) (1-1000)$count",
798 SHARP_STR
799 "Send messages for testing\n"
800 "Send opaque messages\n"
801 "Type code to send\n"
802 "Type code to send\n"
803 "Number of messages to send\n")
804 {
805 sharp_opaque_send(type, 0, 0, 0, count);
806 return CMD_SUCCESS;
807 }
808
809 DEFPY (send_opaque_unicast,
810 send_opaque_unicast_cmd,
811 "sharp send opaque unicast type (1-255) \
812 " FRR_IP_REDIST_STR_ZEBRA "$proto_str \
813 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
814 SHARP_STR
815 "Send messages for testing\n"
816 "Send opaque messages\n"
817 "Send unicast messages\n"
818 "Type code to send\n"
819 "Type code to send\n"
820 FRR_IP_REDIST_HELP_STR_ZEBRA
821 "Daemon instance\n"
822 "Daemon instance\n"
823 "Session ID\n"
824 "Session ID\n"
825 "Number of messages to send\n")
826 {
827 uint32_t proto;
828
829 proto = proto_redistnum(AFI_IP, proto_str);
830
831 sharp_opaque_send(type, proto, instance, session, count);
832
833 return CMD_SUCCESS;
834 }
835
836 DEFPY (send_opaque_reg,
837 send_opaque_reg_cmd,
838 "sharp send opaque <reg$reg | unreg> \
839 " FRR_IP_REDIST_STR_ZEBRA "$proto_str \
840 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
841 SHARP_STR
842 "Send messages for testing\n"
843 "Send opaque messages\n"
844 "Send opaque registration\n"
845 "Send opaque unregistration\n"
846 FRR_IP_REDIST_HELP_STR_ZEBRA
847 "Daemon instance\n"
848 "Daemon instance\n"
849 "Session ID\n"
850 "Session ID\n"
851 "Opaque sub-type code\n"
852 "Opaque sub-type code\n")
853 {
854 int proto;
855
856 proto = proto_redistnum(AFI_IP, proto_str);
857
858 sharp_opaque_reg_send((reg != NULL), proto, instance, session, type);
859 return CMD_SUCCESS;
860 }
861
862 DEFPY (neigh_discover,
863 neigh_discover_cmd,
864 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
865 SHARP_STR
866 "Discover neighbours\n"
867 "Send an ARP/NDP request\n"
868 VRF_CMD_HELP_STR
869 "v4 Destination address\n"
870 "v6 Destination address\n"
871 "Interface name\n")
872 {
873 struct vrf *vrf;
874 struct interface *ifp;
875 struct prefix prefix;
876
877 memset(&prefix, 0, sizeof(prefix));
878
879 if (dst4.s_addr != INADDR_ANY) {
880 prefix.family = AF_INET;
881 prefix.prefixlen = 32;
882 prefix.u.prefix4 = dst4;
883 } else {
884 prefix.family = AF_INET6;
885 prefix.prefixlen = 128;
886 prefix.u.prefix6 = dst6;
887 }
888
889 vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME);
890 if (!vrf) {
891 vty_out(vty, "The vrf NAME specified: %s does not exist\n",
892 vrf_name ? vrf_name : VRF_DEFAULT_NAME);
893 return CMD_WARNING;
894 }
895
896 ifp = if_lookup_by_name_vrf(ifname, vrf);
897 if (ifp == NULL) {
898 vty_out(vty, "%% Can't find interface %s\n", ifname);
899 return CMD_WARNING;
900 }
901
902 sharp_zebra_send_arp(ifp, &prefix);
903
904 return CMD_SUCCESS;
905 }
906
907 DEFPY (import_te,
908 import_te_cmd,
909 "sharp import-te",
910 SHARP_STR
911 "Import Traffic Engineering\n")
912 {
913 sg.ted = ls_ted_new(1, "Sharp", 0);
914 sharp_zebra_register_te();
915
916 return CMD_SUCCESS;
917 }
918
919 DEFPY (sharp_srv6_manager_get_locator_chunk,
920 sharp_srv6_manager_get_locator_chunk_cmd,
921 "sharp srv6-manager get-locator-chunk NAME$locator_name",
922 SHARP_STR
923 "Segment-Routing IPv6\n"
924 "Get SRv6 locator-chunk\n"
925 "SRv6 Locator name\n")
926 {
927 int ret;
928 struct listnode *node;
929 struct sharp_srv6_locator *loc;
930 struct sharp_srv6_locator *loc_found = NULL;
931
932 for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, node, loc)) {
933 if (strcmp(loc->name, locator_name))
934 continue;
935 loc_found = loc;
936 break;
937 }
938 if (!loc_found) {
939 loc = XCALLOC(MTYPE_SRV6_LOCATOR,
940 sizeof(struct sharp_srv6_locator));
941 loc->chunks = list_new();
942 snprintf(loc->name, SRV6_LOCNAME_SIZE, "%s", locator_name);
943 listnode_add(sg.srv6_locators, loc);
944 }
945
946 ret = sharp_zebra_srv6_manager_get_locator_chunk(locator_name);
947 if (ret < 0)
948 return CMD_WARNING_CONFIG_FAILED;
949
950 return CMD_SUCCESS;
951 }
952
953 DEFUN (show_sharp_ted,
954 show_sharp_ted_cmd,
955 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
956 SHOW_STR
957 SHARP_STR
958 "Traffic Engineering Database\n"
959 "MPLS-TE Vertex\n"
960 "MPLS-TE router ID (as an IP address)\n"
961 "MPLS-TE Edge\n"
962 "MPLS-TE Edge ID (as an IP address)\n"
963 "MPLS-TE Subnet\n"
964 "MPLS-TE Subnet ID (as an IP prefix)\n"
965 "Verbose output\n"
966 JSON_STR)
967 {
968 int idx = 0;
969 struct in_addr ip_addr;
970 struct prefix pref;
971 struct ls_vertex *vertex;
972 struct ls_edge *edge;
973 struct ls_subnet *subnet;
974 uint64_t key;
975 bool verbose = false;
976 bool uj = use_json(argc, argv);
977 json_object *json = NULL;
978
979 if (sg.ted == NULL) {
980 vty_out(vty, "MPLS-TE import is not enabled\n");
981 return CMD_WARNING;
982 }
983
984 if (uj)
985 json = json_object_new_object();
986
987 if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "verbose"))
988 verbose = true;
989
990 if (argv_find(argv, argc, "vertex", &idx)) {
991 /* Show Vertex */
992 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
993 if (!inet_aton(argv[idx + 1]->arg, &ip_addr)) {
994 vty_out(vty,
995 "Specified Router ID %s is invalid\n",
996 argv[idx + 1]->arg);
997 return CMD_WARNING_CONFIG_FAILED;
998 }
999 /* Get the Vertex from the Link State Database */
1000 key = ((uint64_t)ip_addr.s_addr) & 0xffffffff;
1001 vertex = ls_find_vertex_by_key(sg.ted, key);
1002 if (!vertex) {
1003 vty_out(vty, "No vertex found for ID %pI4\n",
1004 &ip_addr);
1005 return CMD_WARNING;
1006 }
1007 } else
1008 vertex = NULL;
1009
1010 if (vertex)
1011 ls_show_vertex(vertex, vty, json, verbose);
1012 else
1013 ls_show_vertices(sg.ted, vty, json, verbose);
1014
1015 } else if (argv_find(argv, argc, "edge", &idx)) {
1016 /* Show Edge */
1017 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
1018 if (!inet_aton(argv[idx]->arg, &ip_addr)) {
1019 vty_out(vty,
1020 "Specified Edge ID %s is invalid\n",
1021 argv[idx]->arg);
1022 return CMD_WARNING_CONFIG_FAILED;
1023 }
1024 /* Get the Edge from the Link State Database */
1025 key = ((uint64_t)ip_addr.s_addr) & 0xffffffff;
1026 edge = ls_find_edge_by_key(sg.ted, key);
1027 if (!edge) {
1028 vty_out(vty, "No edge found for ID %pI4\n",
1029 &ip_addr);
1030 return CMD_WARNING;
1031 }
1032 } else
1033 edge = NULL;
1034
1035 if (edge)
1036 ls_show_edge(edge, vty, json, verbose);
1037 else
1038 ls_show_edges(sg.ted, vty, json, verbose);
1039
1040 } else if (argv_find(argv, argc, "subnet", &idx)) {
1041 /* Show Subnet */
1042 if (argv_find(argv, argc, "A.B.C.D/M", &idx)) {
1043 if (!str2prefix(argv[idx]->arg, &pref)) {
1044 vty_out(vty, "Invalid prefix format %s\n",
1045 argv[idx]->arg);
1046 return CMD_WARNING_CONFIG_FAILED;
1047 }
1048 /* Get the Subnet from the Link State Database */
1049 subnet = ls_find_subnet(sg.ted, pref);
1050 if (!subnet) {
1051 vty_out(vty, "No subnet found for ID %pFX\n",
1052 &pref);
1053 return CMD_WARNING;
1054 }
1055 } else
1056 subnet = NULL;
1057
1058 if (subnet)
1059 ls_show_subnet(subnet, vty, json, verbose);
1060 else
1061 ls_show_subnets(sg.ted, vty, json, verbose);
1062
1063 } else {
1064 /* Show the complete TED */
1065 ls_show_ted(sg.ted, vty, json, verbose);
1066 }
1067
1068 if (uj) {
1069 vty_out(vty, "%s\n",
1070 json_object_to_json_string_ext(
1071 json, JSON_C_TO_STRING_PRETTY));
1072 json_object_free(json);
1073 }
1074
1075 return CMD_SUCCESS;
1076 }
1077
1078 DEFPY (sharp_srv6_manager_release_locator_chunk,
1079 sharp_srv6_manager_release_locator_chunk_cmd,
1080 "sharp srv6-manager release-locator-chunk NAME$locator_name",
1081 SHARP_STR
1082 "Segment-Routing IPv6\n"
1083 "Release SRv6 locator-chunk\n"
1084 "SRv6 Locator name\n")
1085 {
1086 int ret;
1087 struct listnode *loc_node;
1088 struct sharp_srv6_locator *loc;
1089
1090 for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) {
1091 if (!strcmp(loc->name, locator_name)) {
1092 list_delete_all_node(loc->chunks);
1093 list_delete(&loc->chunks);
1094 listnode_delete(sg.srv6_locators, loc);
1095 break;
1096 }
1097 }
1098
1099 ret = sharp_zebra_srv6_manager_release_locator_chunk(locator_name);
1100 if (ret < 0)
1101 return CMD_WARNING_CONFIG_FAILED;
1102
1103 return CMD_SUCCESS;
1104 }
1105
1106 DEFPY (show_sharp_segment_routing_srv6,
1107 show_sharp_segment_routing_srv6_cmd,
1108 "show sharp segment-routing srv6 [json]",
1109 SHOW_STR
1110 SHARP_STR
1111 "Segment-Routing\n"
1112 "Segment-Routing IPv6\n"
1113 JSON_STR)
1114 {
1115 char str[256];
1116 struct listnode *loc_node;
1117 struct listnode *chunk_node;
1118 struct sharp_srv6_locator *loc;
1119 struct prefix_ipv6 *chunk;
1120 bool uj = use_json(argc, argv);
1121 json_object *jo_locs = NULL;
1122 json_object *jo_loc = NULL;
1123 json_object *jo_chunks = NULL;
1124
1125 if (uj) {
1126 jo_locs = json_object_new_array();
1127 for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) {
1128 jo_loc = json_object_new_object();
1129 json_object_array_add(jo_locs, jo_loc);
1130 json_object_string_add(jo_loc, "name", loc->name);
1131 jo_chunks = json_object_new_array();
1132 json_object_object_add(jo_loc, "chunks", jo_chunks);
1133 for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node,
1134 chunk)) {
1135 prefix2str(chunk, str, sizeof(str));
1136 json_array_string_add(jo_chunks, str);
1137 }
1138 }
1139
1140 vty_out(vty, "%s\n", json_object_to_json_string_ext(
1141 jo_locs, JSON_C_TO_STRING_PRETTY));
1142 json_object_free(jo_locs);
1143 } else {
1144 for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) {
1145 vty_out(vty, "Locator %s has %d prefix chunks\n",
1146 loc->name, listcount(loc->chunks));
1147 for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node,
1148 chunk)) {
1149 prefix2str(chunk, str, sizeof(str));
1150 vty_out(vty, " %s\n", str);
1151 }
1152 vty_out(vty, "\n");
1153 }
1154 }
1155
1156 return CMD_SUCCESS;
1157 }
1158
1159 void sharp_vty_init(void)
1160 {
1161 install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
1162 install_element(ENABLE_NODE, &install_routes_cmd);
1163 install_element(ENABLE_NODE, &install_seg6_routes_cmd);
1164 install_element(ENABLE_NODE, &install_seg6local_routes_cmd);
1165 install_element(ENABLE_NODE, &remove_routes_cmd);
1166 install_element(ENABLE_NODE, &vrf_label_cmd);
1167 install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd);
1168 install_element(ENABLE_NODE, &watch_redistribute_cmd);
1169 install_element(ENABLE_NODE, &watch_nexthop_v6_cmd);
1170 install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
1171 install_element(ENABLE_NODE, &sharp_lsp_prefix_v4_cmd);
1172 install_element(ENABLE_NODE, &sharp_remove_lsp_prefix_v4_cmd);
1173 install_element(ENABLE_NODE, &logpump_cmd);
1174 install_element(ENABLE_NODE, &create_session_cmd);
1175 install_element(ENABLE_NODE, &remove_session_cmd);
1176 install_element(ENABLE_NODE, &send_opaque_cmd);
1177 install_element(ENABLE_NODE, &send_opaque_unicast_cmd);
1178 install_element(ENABLE_NODE, &send_opaque_reg_cmd);
1179 install_element(ENABLE_NODE, &neigh_discover_cmd);
1180 install_element(ENABLE_NODE, &import_te_cmd);
1181
1182 install_element(ENABLE_NODE, &show_debugging_sharpd_cmd);
1183 install_element(ENABLE_NODE, &show_sharp_ted_cmd);
1184
1185 install_element(ENABLE_NODE, &sharp_srv6_manager_get_locator_chunk_cmd);
1186 install_element(ENABLE_NODE,
1187 &sharp_srv6_manager_release_locator_chunk_cmd);
1188 install_element(ENABLE_NODE, &show_sharp_segment_routing_srv6_cmd);
1189
1190 return;
1191 }