1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) Cumulus Networks, Inc.
16 #include "nexthop_group.h"
18 #include "link_state.h"
22 #include "sharpd/sharp_globals.h"
23 #include "sharpd/sharp_zebra.h"
24 #include "sharpd/sharp_nht.h"
25 #include "sharpd/sharp_vty.h"
26 #include "sharpd/sharp_vty_clippy.c"
28 DEFINE_MTYPE_STATIC(SHARPD
, SRV6_LOCATOR
, "SRv6 Locator");
30 DEFPY(watch_redistribute
, watch_redistribute_cmd
,
31 "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD
,
32 "Sharp routing Protocol\n"
34 "The vrf we would like to watch if non-default\n"
35 "The NAME of the vrf\n"
36 "Redistribute into Sharp\n"
37 FRR_REDIST_HELP_STR_SHARPD
)
43 vrf_name
= VRF_DEFAULT_NAME
;
44 vrf
= vrf_lookup_by_name(vrf_name
);
46 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
51 source
= proto_redistnum(AFI_IP
, argv
[argc
-1]->text
);
52 sharp_redistribute_vrf(vrf
, source
);
57 DEFPY(watch_nexthop_v6
, watch_nexthop_v6_cmd
,
58 "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
59 "Sharp routing Protocol\n"
61 "The vrf we would like to watch if non-default\n"
62 "The NAME of the vrf\n"
63 "Watch for nexthop changes\n"
64 "The v6 nexthop to signal for watching\n"
65 "Watch for import check changes\n"
66 "The v6 prefix to signal for watching\n"
67 "Should the route be connected\n")
74 vrf_name
= VRF_DEFAULT_NAME
;
75 vrf
= vrf_lookup_by_name(vrf_name
);
77 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
82 memset(&p
, 0, sizeof(p
));
86 p
.prefixlen
= IPV6_MAX_BITLEN
;
87 memcpy(&p
.u
.prefix6
, &nhop
, IPV6_MAX_BYTELEN
);
91 prefix_copy(&p
, inhop
);
94 sharp_nh_tracker_get(&p
);
95 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
101 DEFPY(watch_nexthop_v4
, watch_nexthop_v4_cmd
,
102 "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
103 "Sharp routing Protocol\n"
104 "Watch for changes\n"
105 "The vrf we would like to watch if non-default\n"
106 "The NAME of the vrf\n"
107 "Watch for nexthop changes\n"
108 "The v4 address to signal for watching\n"
109 "Watch for import check changes\n"
110 "The v4 prefix for import check to watch\n"
111 "Should the route be connected\n")
118 vrf_name
= VRF_DEFAULT_NAME
;
119 vrf
= vrf_lookup_by_name(vrf_name
);
121 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
126 memset(&p
, 0, sizeof(p
));
130 p
.prefixlen
= IPV4_MAX_BITLEN
;
136 prefix_copy(&p
, inhop
);
139 sharp_nh_tracker_get(&p
);
140 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
146 DEFPY(sharp_nht_data_dump
,
147 sharp_nht_data_dump_cmd
,
148 "sharp data nexthop",
149 "Sharp routing Protocol\n"
150 "Data about what is going on\n"
151 "Nexthop information\n")
153 sharp_nh_tracker_dump(vty
);
158 DEFPY (install_routes_data_dump
,
159 install_routes_data_dump_cmd
,
161 "Sharp routing Protocol\n"
162 "Data about what is going on\n"
163 "Route Install/Removal Information\n")
167 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
168 vty_out(vty
, "Prefix: %pFX Total: %u %u %u Time: %jd.%ld\n",
169 &sg
.r
.orig_prefix
, sg
.r
.total_routes
, sg
.r
.installed_routes
,
170 sg
.r
.removed_routes
, (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
175 DEFPY (install_routes
,
177 "sharp install routes [vrf NAME$vrf_name]\
178 <A.B.C.D$start4|X:X::X:X$start6>\
179 <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
180 nexthop-group NHGNAME$nexthop_group>\
181 [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
182 (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]",
183 "Sharp routing Protocol\n"
184 "install some routes\n"
185 "Routes to install\n"
186 "The vrf we would like to install into if non-default\n"
187 "The NAME of the vrf\n"
188 "v4 Address to start /32 generation at\n"
189 "v6 Address to start /32 generation at\n"
190 "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
191 "V4 Nexthop address to use\n"
192 "V6 Nexthop address to use\n"
193 "Nexthop-Group to use\n"
194 "The Name of the nexthop-group\n"
195 "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
196 "Backup V4 Nexthop address to use\n"
197 "Backup V6 Nexthop address to use\n"
198 "How many to create\n"
201 "Should we repeat this command\n"
202 "How many times to repeat this command\n"
203 "What opaque data to send down\n"
207 struct prefix prefix
;
211 sg
.r
.total_routes
= routes
;
212 sg
.r
.installed_routes
= 0;
215 sg
.r
.repeat
= rpt
* 2;
219 memset(&prefix
, 0, sizeof(prefix
));
220 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
221 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
222 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
223 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
224 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
225 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
226 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
228 if (start4
.s_addr
!= INADDR_ANY
) {
229 prefix
.family
= AF_INET
;
230 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
231 prefix
.u
.prefix4
= start4
;
233 prefix
.family
= AF_INET6
;
234 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
235 prefix
.u
.prefix6
= start6
;
237 sg
.r
.orig_prefix
= prefix
;
240 vrf_name
= VRF_DEFAULT_NAME
;
242 vrf
= vrf_lookup_by_name(vrf_name
);
244 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
249 /* Explicit backup not available with named nexthop-group */
250 if (backup
&& nexthop_group
) {
251 vty_out(vty
, "%% Invalid: cannot specify both nexthop-group and backup\n");
256 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
259 "Specified Nexthop Group: %s does not exist\n",
264 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
266 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
268 /* Use group's backup nexthop info if present */
269 if (nhgc
->backup_list_name
[0]) {
270 struct nexthop_group_cmd
*bnhgc
=
271 nhgc_find(nhgc
->backup_list_name
);
274 vty_out(vty
, "%% Backup group %s not found for group %s\n",
275 nhgc
->backup_list_name
,
280 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
281 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
284 if (nexthop4
.s_addr
!= INADDR_ANY
) {
285 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
286 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
288 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
289 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
292 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
293 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
296 /* Use single backup nexthop if specified */
298 /* Set flag and index in primary nexthop */
299 SET_FLAG(sg
.r
.nhop
.flags
, NEXTHOP_FLAG_HAS_BACKUP
);
300 sg
.r
.nhop
.backup_num
= 1;
301 sg
.r
.nhop
.backup_idx
[0] = 0;
303 if (backup_nexthop4
.s_addr
!= INADDR_ANY
) {
304 sg
.r
.backup_nhop
.gate
.ipv4
= backup_nexthop4
;
305 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV4
;
307 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
308 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
311 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
312 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
316 strlcpy(sg
.r
.opaque
, opaque
, ZAPI_MESSAGE_OPAQUE_LENGTH
);
318 sg
.r
.opaque
[0] = '\0';
320 sg
.r
.inst
= instance
;
321 sg
.r
.vrf_id
= vrf
->vrf_id
;
323 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, nhgid
,
324 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
325 rts
, 0, sg
.r
.opaque
);
330 DEFPY (install_seg6_routes
,
331 install_seg6_routes_cmd
,
332 "sharp install seg6-routes [vrf NAME$vrf_name]\
333 <A.B.C.D$start4|X:X::X:X$start6>\
334 nexthop-seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg\
335 (1-1000000)$routes [repeat (2-1000)$rpt]",
336 "Sharp routing Protocol\n"
337 "install some routes\n"
338 "Routes to install\n"
339 "The vrf we would like to install into if non-default\n"
340 "The NAME of the vrf\n"
341 "v4 Address to start /32 generation at\n"
342 "v6 Address to start /32 generation at\n"
343 "Nexthop-seg6 to use\n"
344 "V6 Nexthop address to use\n"
346 "Segment List to use\n"
347 "How many to create\n"
348 "Should we repeat this command\n"
349 "How many times to repeat this command\n")
352 struct prefix prefix
;
353 uint32_t route_flags
= 0;
355 sg
.r
.total_routes
= routes
;
356 sg
.r
.installed_routes
= 0;
359 sg
.r
.repeat
= rpt
* 2;
363 memset(&prefix
, 0, sizeof(prefix
));
364 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
365 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
366 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
367 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
368 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
369 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
370 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
371 sg
.r
.opaque
[0] = '\0';
374 if (start4
.s_addr
!= INADDR_ANY
) {
375 prefix
.family
= AF_INET
;
376 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
377 prefix
.u
.prefix4
= start4
;
379 prefix
.family
= AF_INET6
;
380 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
381 prefix
.u
.prefix6
= start6
;
383 sg
.r
.orig_prefix
= prefix
;
386 vrf_name
= VRF_DEFAULT_NAME
;
388 vrf
= vrf_lookup_by_name(vrf_name
);
390 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
395 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
396 sg
.r
.nhop
.gate
.ipv6
= seg6_nh6
;
397 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
398 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
399 nexthop_add_srv6_seg6(&sg
.r
.nhop
, &seg6_seg
);
401 sg
.r
.vrf_id
= vrf
->vrf_id
;
402 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, 0,
403 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
404 routes
, route_flags
, sg
.r
.opaque
);
409 DEFPY (install_seg6local_routes
,
410 install_seg6local_routes_cmd
,
411 "sharp install seg6local-routes [vrf NAME$vrf_name]\
413 nexthop-seg6local NAME$seg6l_oif\
415 End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
416 End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
417 End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
418 End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
419 End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table|\
420 End_DT46$seg6l_enddt46 (1-4294967295)$seg6l_enddt46_table>\
421 (1-1000000)$routes [repeat (2-1000)$rpt]",
422 "Sharp routing Protocol\n"
423 "install some routes\n"
424 "Routes to install\n"
425 "The vrf we would like to install into if non-default\n"
426 "The NAME of the vrf\n"
427 "v6 Address to start /32 generation at\n"
428 "Nexthop-seg6local to use\n"
429 "Output device to use\n"
430 "SRv6 End function to use\n"
431 "SRv6 End.X function to use\n"
432 "V6 Nexthop address to use\n"
433 "SRv6 End.T function to use\n"
434 "Redirect table id to use\n"
435 "SRv6 End.DX4 function to use\n"
436 "V4 Nexthop address to use\n"
437 "SRv6 End.DT6 function to use\n"
438 "Redirect table id to use\n"
439 "SRv6 End.DT4 function to use\n"
440 "Redirect table id to use\n"
441 "SRv6 End.DT46 function to use\n"
442 "Redirect table id to use\n"
443 "How many to create\n"
444 "Should we repeat this command\n"
445 "How many times to repeat this command\n")
448 uint32_t route_flags
= 0;
449 struct seg6local_context ctx
= {};
450 enum seg6local_action_t action
;
452 sg
.r
.total_routes
= routes
;
453 sg
.r
.installed_routes
= 0;
456 sg
.r
.repeat
= rpt
* 2;
460 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
461 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
462 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
463 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
464 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
465 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
466 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
467 sg
.r
.opaque
[0] = '\0';
469 sg
.r
.orig_prefix
.family
= AF_INET6
;
470 sg
.r
.orig_prefix
.prefixlen
= 128;
471 sg
.r
.orig_prefix
.u
.prefix6
= start6
;
474 vrf_name
= VRF_DEFAULT_NAME
;
476 vrf
= vrf_lookup_by_name(vrf_name
);
478 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
484 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DX4
;
485 ctx
.nh4
= seg6l_enddx4_nh4
;
486 } else if (seg6l_endx
) {
487 action
= ZEBRA_SEG6_LOCAL_ACTION_END_X
;
488 ctx
.nh6
= seg6l_endx_nh6
;
489 } else if (seg6l_endt
) {
490 action
= ZEBRA_SEG6_LOCAL_ACTION_END_T
;
491 ctx
.table
= seg6l_endt_table
;
492 } else if (seg6l_enddt6
) {
493 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT6
;
494 ctx
.table
= seg6l_enddt6_table
;
495 } else if (seg6l_enddt4
) {
496 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT4
;
497 ctx
.table
= seg6l_enddt4_table
;
498 } else if (seg6l_enddt46
) {
499 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT46
;
500 ctx
.table
= seg6l_enddt46_table
;
502 action
= ZEBRA_SEG6_LOCAL_ACTION_END
;
505 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
506 sg
.r
.nhop
.ifindex
= ifname2ifindex(seg6l_oif
, vrf
->vrf_id
);
507 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
508 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
509 nexthop_add_srv6_seg6local(&sg
.r
.nhop
, action
, &ctx
);
511 sg
.r
.vrf_id
= vrf
->vrf_id
;
512 sharp_install_routes_helper(&sg
.r
.orig_prefix
, sg
.r
.vrf_id
, sg
.r
.inst
,
514 &sg
.r
.backup_nhop_group
, routes
,
515 route_flags
, sg
.r
.opaque
);
520 DEFPY(vrf_label
, vrf_label_cmd
,
521 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
522 "Sharp Routing Protocol\n"
523 "Give a vrf a label\n"
524 "Pop and forward for IPv4\n"
525 "Pop and forward for IPv6\n"
527 "The label to use, 0 specifies remove the label installed from previous\n"
528 "Specified range to use\n")
531 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
533 if (strcmp(vrf_name
, "default") == 0)
534 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
536 vrf
= vrf_lookup_by_name(vrf_name
);
539 vty_out(vty
, "Unable to find vrf you silly head\n");
540 return CMD_WARNING_CONFIG_FAILED
;
544 label
= MPLS_LABEL_NONE
;
546 vrf_label_add(vrf
->vrf_id
, afi
, label
);
550 DEFPY (remove_routes
,
552 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
553 "Sharp Routing Protocol\n"
554 "Remove some routes\n"
556 "The vrf we would like to remove from if non-default\n"
557 "The NAME of the vrf\n"
560 "Routes to uninstall\n"
562 "Value of instance\n")
565 struct prefix prefix
;
567 sg
.r
.total_routes
= routes
;
568 sg
.r
.removed_routes
= 0;
571 memset(&prefix
, 0, sizeof(prefix
));
573 if (start4
.s_addr
!= INADDR_ANY
) {
574 prefix
.family
= AF_INET
;
575 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
576 prefix
.u
.prefix4
= start4
;
578 prefix
.family
= AF_INET6
;
579 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
580 prefix
.u
.prefix6
= start6
;
583 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
585 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
586 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
590 sg
.r
.inst
= instance
;
591 sg
.r
.vrf_id
= vrf
->vrf_id
;
593 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
599 DEFUN_NOSH (show_debugging_sharpd
,
600 show_debugging_sharpd_cmd
,
601 "show debugging [sharp]",
604 "Sharp Information\n")
606 vty_out(vty
, "Sharp debugging status:\n");
608 cmd_show_lib_debugs(vty
);
613 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
614 "sharp lsp [update]$update (0-100000)$inlabel\
615 nexthop-group NHGNAME$nhgname\
616 [prefix A.B.C.D/M$pfx\
617 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
618 "Sharp Routing Protocol\n"
621 "The ingress label to use\n"
622 "Use nexthops from a nexthop-group\n"
623 "The nexthop-group name\n"
625 "The v4 prefix to label\n"
626 FRR_IP_REDIST_HELP_STR_ZEBRA
630 struct nexthop_group_cmd
*nhgc
= NULL
;
631 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
632 struct nexthop_group
*backup_nhg
= NULL
;
633 struct prefix p
= {};
637 update_p
= (update
!= NULL
);
639 /* We're offered a v4 prefix */
640 if (pfx
->family
> 0 && type_str
) {
641 p
.family
= pfx
->family
;
642 p
.prefixlen
= pfx
->prefixlen
;
643 p
.u
.prefix4
= pfx
->prefix
;
645 type
= proto_redistnum(AFI_IP
, type_str
);
647 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
650 } else if (pfx
->family
> 0 || type_str
) {
651 vty_out(vty
, "%% Must supply both prefix and type\n");
655 nhgc
= nhgc_find(nhgname
);
657 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
662 if (nhgc
->nhg
.nexthop
== NULL
) {
663 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
667 /* Use group's backup nexthop info if present */
668 if (nhgc
->backup_list_name
[0]) {
669 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
673 "%% Backup group %s not found for group %s\n",
674 nhgc
->backup_list_name
,
678 backup_nhg
= &(backup_nhgc
->nhg
);
681 if (sharp_install_lsps_helper(true /*install*/, update_p
,
682 pfx
->family
> 0 ? &p
: NULL
,
683 type
, instance
, inlabel
,
684 &(nhgc
->nhg
), backup_nhg
) == 0)
687 vty_out(vty
, "%% LSP install failed!\n");
692 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
695 [nexthop-group NHGNAME$nhgname] \
696 [prefix A.B.C.D/M$pfx\
697 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
698 "Sharp Routing Protocol\n"
701 "The ingress label\n"
702 "Use nexthops from a nexthop-group\n"
703 "The nexthop-group name\n"
704 "Specify a v4 prefix\n"
705 "The v4 prefix to label\n"
706 FRR_IP_REDIST_HELP_STR_ZEBRA
710 struct nexthop_group_cmd
*nhgc
= NULL
;
711 struct prefix p
= {};
713 struct nexthop_group
*nhg
= NULL
;
715 /* We're offered a v4 prefix */
716 if (pfx
->family
> 0 && type_str
) {
717 p
.family
= pfx
->family
;
718 p
.prefixlen
= pfx
->prefixlen
;
719 p
.u
.prefix4
= pfx
->prefix
;
721 type
= proto_redistnum(AFI_IP
, type_str
);
723 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
726 } else if (pfx
->family
> 0 || type_str
) {
727 vty_out(vty
, "%% Must supply both prefix and type\n");
732 nhgc
= nhgc_find(nhgname
);
734 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
739 if (nhgc
->nhg
.nexthop
== NULL
) {
740 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
747 if (sharp_install_lsps_helper(false /*!install*/, false,
748 pfx
->family
> 0 ? &p
: NULL
,
749 type
, instance
, inlabel
, nhg
, NULL
) == 0)
752 vty_out(vty
, "%% LSP remove failed!\n");
759 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
760 "Sharp Routing Protocol\n"
761 "Generate bulk log messages for testing\n"
762 "Duration of run (s)\n"
763 "Duration of run (s)\n"
764 "Frequency of bursts (s^-1)\n"
765 "Frequency of bursts (s^-1)\n"
766 "Number of log messages per each burst\n"
767 "Number of log messages per each burst\n")
769 sharp_logpump_run(vty
, duration
, frequency
, burst
);
773 DEFPY (create_session
,
775 "sharp create session (1-1024)",
776 "Sharp Routing Protocol\n"
778 "Create a test session\n"
781 if (sharp_zclient_create(session
) != 0) {
782 vty_out(vty
, "%% Client session error\n");
789 DEFPY (remove_session
,
791 "sharp remove session (1-1024)",
792 "Sharp Routing Protocol\n"
794 "Remove a test session\n"
797 sharp_zclient_delete(session
);
803 "sharp send opaque type (1-255) (1-1000)$count",
805 "Send messages for testing\n"
806 "Send opaque messages\n"
807 "Type code to send\n"
808 "Type code to send\n"
809 "Number of messages to send\n")
811 sharp_opaque_send(type
, 0, 0, 0, count
);
815 DEFPY (send_opaque_unicast
,
816 send_opaque_unicast_cmd
,
817 "sharp send opaque unicast type (1-255) \
818 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
819 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
821 "Send messages for testing\n"
822 "Send opaque messages\n"
823 "Send unicast messages\n"
824 "Type code to send\n"
825 "Type code to send\n"
826 FRR_IP_REDIST_HELP_STR_ZEBRA
831 "Number of messages to send\n")
835 proto
= proto_redistnum(AFI_IP
, proto_str
);
837 sharp_opaque_send(type
, proto
, instance
, session
, count
);
842 DEFPY (send_opaque_reg
,
844 "sharp send opaque <reg$reg | unreg> \
845 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
846 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
848 "Send messages for testing\n"
849 "Send opaque messages\n"
850 "Send opaque registration\n"
851 "Send opaque unregistration\n"
852 FRR_IP_REDIST_HELP_STR_ZEBRA
857 "Opaque sub-type code\n"
858 "Opaque sub-type code\n")
862 proto
= proto_redistnum(AFI_IP
, proto_str
);
864 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
868 DEFPY (neigh_discover
,
870 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
872 "Discover neighbours\n"
873 "Send an ARP/NDP request\n"
875 "v4 Destination address\n"
876 "v6 Destination address\n"
880 struct interface
*ifp
;
881 struct prefix prefix
;
883 memset(&prefix
, 0, sizeof(prefix
));
885 if (dst4
.s_addr
!= INADDR_ANY
) {
886 prefix
.family
= AF_INET
;
887 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
888 prefix
.u
.prefix4
= dst4
;
890 prefix
.family
= AF_INET6
;
891 prefix
.prefixlen
= 128;
892 prefix
.u
.prefix6
= dst6
;
895 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
897 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
898 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
902 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
904 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
908 sharp_zebra_send_arp(ifp
, &prefix
);
917 "Import Traffic Engineering\n")
919 sg
.ted
= ls_ted_new(1, "Sharp", 0);
920 sharp_zebra_register_te();
925 static void sharp_srv6_locator_chunk_free(struct prefix_ipv6
*chunk
)
927 prefix_ipv6_free((struct prefix_ipv6
**)&chunk
);
930 DEFPY (sharp_srv6_manager_get_locator_chunk
,
931 sharp_srv6_manager_get_locator_chunk_cmd
,
932 "sharp srv6-manager get-locator-chunk NAME$locator_name",
934 "Segment-Routing IPv6\n"
935 "Get SRv6 locator-chunk\n"
936 "SRv6 Locator name\n")
939 struct listnode
*node
;
940 struct sharp_srv6_locator
*loc
;
941 struct sharp_srv6_locator
*loc_found
= NULL
;
943 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, node
, loc
)) {
944 if (strcmp(loc
->name
, locator_name
))
950 loc
= XCALLOC(MTYPE_SRV6_LOCATOR
,
951 sizeof(struct sharp_srv6_locator
));
952 loc
->chunks
= list_new();
954 (void (*)(void *))sharp_srv6_locator_chunk_free
;
955 snprintf(loc
->name
, SRV6_LOCNAME_SIZE
, "%s", locator_name
);
956 listnode_add(sg
.srv6_locators
, loc
);
959 ret
= sharp_zebra_srv6_manager_get_locator_chunk(locator_name
);
961 return CMD_WARNING_CONFIG_FAILED
;
966 DEFUN (show_sharp_ted
,
968 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
971 "Traffic Engineering Database\n"
973 "MPLS-TE router ID (as an IP address)\n"
975 "MPLS-TE Edge ID (as an IP address)\n"
977 "MPLS-TE Subnet ID (as an IP prefix)\n"
982 struct in_addr ip_addr
;
984 struct ls_vertex
*vertex
;
985 struct ls_edge
*edge
;
986 struct ls_subnet
*subnet
;
988 bool verbose
= false;
989 bool uj
= use_json(argc
, argv
);
990 json_object
*json
= NULL
;
992 if (sg
.ted
== NULL
) {
993 vty_out(vty
, "MPLS-TE import is not enabled\n");
998 json
= json_object_new_object();
1000 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
1003 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1005 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1006 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
1008 "Specified Router ID %s is invalid\n",
1009 argv
[idx
+ 1]->arg
);
1010 return CMD_WARNING_CONFIG_FAILED
;
1012 /* Get the Vertex from the Link State Database */
1013 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1014 vertex
= ls_find_vertex_by_key(sg
.ted
, key
);
1016 vty_out(vty
, "No vertex found for ID %pI4\n",
1024 ls_show_vertex(vertex
, vty
, json
, verbose
);
1026 ls_show_vertices(sg
.ted
, vty
, json
, verbose
);
1028 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1030 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1031 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
1033 "Specified Edge ID %s is invalid\n",
1035 return CMD_WARNING_CONFIG_FAILED
;
1037 /* Get the Edge from the Link State Database */
1038 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1039 edge
= ls_find_edge_by_key(sg
.ted
, key
);
1041 vty_out(vty
, "No edge found for ID %pI4\n",
1049 ls_show_edge(edge
, vty
, json
, verbose
);
1051 ls_show_edges(sg
.ted
, vty
, json
, verbose
);
1053 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1055 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1056 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1057 vty_out(vty
, "Invalid prefix format %s\n",
1059 return CMD_WARNING_CONFIG_FAILED
;
1061 /* Get the Subnet from the Link State Database */
1062 subnet
= ls_find_subnet(sg
.ted
, pref
);
1064 vty_out(vty
, "No subnet found for ID %pFX\n",
1072 ls_show_subnet(subnet
, vty
, json
, verbose
);
1074 ls_show_subnets(sg
.ted
, vty
, json
, verbose
);
1077 /* Show the complete TED */
1078 ls_show_ted(sg
.ted
, vty
, json
, verbose
);
1082 vty_json(vty
, json
);
1087 DEFPY (sharp_srv6_manager_release_locator_chunk
,
1088 sharp_srv6_manager_release_locator_chunk_cmd
,
1089 "sharp srv6-manager release-locator-chunk NAME$locator_name",
1091 "Segment-Routing IPv6\n"
1092 "Release SRv6 locator-chunk\n"
1093 "SRv6 Locator name\n")
1096 struct listnode
*loc_node
;
1097 struct sharp_srv6_locator
*loc
;
1099 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1100 if (!strcmp(loc
->name
, locator_name
)) {
1101 list_delete_all_node(loc
->chunks
);
1102 list_delete(&loc
->chunks
);
1103 listnode_delete(sg
.srv6_locators
, loc
);
1104 XFREE(MTYPE_SRV6_LOCATOR
, loc
);
1109 ret
= sharp_zebra_srv6_manager_release_locator_chunk(locator_name
);
1111 return CMD_WARNING_CONFIG_FAILED
;
1116 DEFPY (show_sharp_segment_routing_srv6
,
1117 show_sharp_segment_routing_srv6_cmd
,
1118 "show sharp segment-routing srv6 [json]",
1122 "Segment-Routing IPv6\n"
1126 struct listnode
*loc_node
;
1127 struct listnode
*chunk_node
;
1128 struct sharp_srv6_locator
*loc
;
1129 struct prefix_ipv6
*chunk
;
1130 bool uj
= use_json(argc
, argv
);
1131 json_object
*jo_locs
= NULL
;
1132 json_object
*jo_loc
= NULL
;
1133 json_object
*jo_chunks
= NULL
;
1136 jo_locs
= json_object_new_array();
1137 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1138 jo_loc
= json_object_new_object();
1139 json_object_array_add(jo_locs
, jo_loc
);
1140 json_object_string_add(jo_loc
, "name", loc
->name
);
1141 jo_chunks
= json_object_new_array();
1142 json_object_object_add(jo_loc
, "chunks", jo_chunks
);
1143 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1145 prefix2str(chunk
, str
, sizeof(str
));
1146 json_array_string_add(jo_chunks
, str
);
1150 vty_json(vty
, jo_locs
);
1152 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1153 vty_out(vty
, "Locator %s has %d prefix chunks\n",
1154 loc
->name
, listcount(loc
->chunks
));
1155 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1157 prefix2str(chunk
, str
, sizeof(str
));
1158 vty_out(vty
, " %s\n", str
);
1167 DEFPY (show_sharp_cspf
,
1168 show_sharp_cspf_cmd
,
1169 "show sharp cspf source <A.B.C.D$src4|X:X::X:X$src6> \
1170 destination <A.B.C.D$dst4|X:X::X:X$dst6> \
1171 <metric|te-metric|delay> (0-16777215)$cost \
1172 [rsv-bw (0-7)$cos BANDWIDTH$bw]",
1175 "Constraint Shortest Path First path computation\n"
1176 "Source of the path\n"
1177 "IPv4 Source address in dot decimal A.B.C.D\n"
1178 "IPv6 Source address as X:X:X:X\n"
1179 "Destination of the path\n"
1180 "IPv4 Destination address in dot decimal A.B.C.D\n"
1181 "IPv6 Destination address as X:X:X:X\n"
1183 "Maximum TE Metric\n"
1185 "Value of Maximum cost\n"
1186 "Reserved Bandwidth of this path\n"
1187 "Class of Service or Priority level\n"
1188 "Bytes/second (IEEE floating point format)\n")
1192 struct constraints csts
;
1193 struct c_path
*path
;
1194 struct listnode
*node
;
1195 struct ls_edge
*edge
;
1198 if (sg
.ted
== NULL
) {
1199 vty_out(vty
, "MPLS-TE import is not enabled\n");
1203 if ((src4
.s_addr
!= INADDR_ANY
&& dst4
.s_addr
== INADDR_ANY
) ||
1204 (src4
.s_addr
== INADDR_ANY
&& dst4
.s_addr
!= INADDR_ANY
)) {
1205 vty_out(vty
, "Don't mix IPv4 and IPv6 addresses\n");
1210 memset(&csts
, 0, sizeof(struct constraints
));
1211 if (argv_find(argv
, argc
, "metric", &idx
)) {
1212 csts
.ctype
= CSPF_METRIC
;
1216 if (argv_find(argv
, argc
, "te-metric", &idx
)) {
1217 csts
.ctype
= CSPF_TE_METRIC
;
1221 if (argv_find(argv
, argc
, "delay", &idx
)) {
1222 csts
.ctype
= CSPF_DELAY
;
1226 if (sscanf(bw
, "%g", &csts
.bw
) != 1) {
1227 vty_out(vty
, "Bandwidth constraints: fscanf: %s\n",
1228 safe_strerror(errno
));
1229 return CMD_WARNING_CONFIG_FAILED
;
1234 /* Initialize and call point-to-point Path computation */
1235 if (src4
.s_addr
!= INADDR_ANY
)
1236 algo
= cspf_init_v4(NULL
, sg
.ted
, src4
, dst4
, &csts
);
1238 algo
= cspf_init_v6(NULL
, sg
.ted
, src6
, dst6
, &csts
);
1239 path
= compute_p2p_path(algo
, sg
.ted
);
1243 vty_out(vty
, "Path computation failed without error\n");
1246 if (path
->status
!= SUCCESS
) {
1247 vty_out(vty
, "Path computation failed: %d\n", path
->status
);
1251 vty_out(vty
, "Path computation success\n");
1252 vty_out(vty
, "\tCost: %d\n", path
->weight
);
1253 vty_out(vty
, "\tEdges:");
1254 for (ALL_LIST_ELEMENTS_RO(path
->edges
, node
, edge
)) {
1255 if (src4
.s_addr
!= INADDR_ANY
)
1256 vty_out(vty
, " %pI4",
1257 &edge
->attributes
->standard
.remote
);
1259 vty_out(vty
, " %pI6",
1260 &edge
->attributes
->standard
.remote6
);
1267 static struct interface
*if_lookup_vrf_all(const char *ifname
)
1269 struct interface
*ifp
;
1272 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1273 ifp
= if_lookup_by_name(ifname
, vrf
->vrf_id
);
1281 DEFPY (sharp_interface_protodown
,
1282 sharp_interface_protodown_cmd
,
1283 "sharp interface IFNAME$ifname protodown",
1287 "Set interface protodown\n")
1289 struct interface
*ifp
;
1291 ifp
= if_lookup_vrf_all(ifname
);
1294 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1298 if (sharp_zebra_send_interface_protodown(ifp
, true) != 0)
1304 DEFPY (no_sharp_interface_protodown
,
1305 no_sharp_interface_protodown_cmd
,
1306 "no sharp interface IFNAME$ifname protodown",
1311 "Set interface protodown\n")
1313 struct interface
*ifp
;
1315 ifp
= if_lookup_vrf_all(ifname
);
1318 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1322 if (sharp_zebra_send_interface_protodown(ifp
, false) != 0)
1328 DEFPY (tc_filter_rate
,
1330 "sharp tc dev IFNAME$ifname \
1331 source <A.B.C.D/M|X:X::X:X/M>$src \
1332 destination <A.B.C.D/M|X:X::X:X/M>$dst \
1333 ip-protocol <tcp|udp>$ip_proto \
1334 src-port (1-65535)$src_port \
1335 dst-port (1-65535)$dst_port \
1339 "TC interface (for qdisc, class, filter)\n"
1340 "TC interface name\n"
1341 "TC filter source\n"
1342 "TC filter source IPv4 prefix\n"
1343 "TC filter source IPv6 prefix\n"
1344 "TC filter destination\n"
1345 "TC filter destination IPv4 prefix\n"
1346 "TC filter destination IPv6 prefix\n"
1347 "TC filter IP protocol\n"
1348 "TC filter IP protocol TCP\n"
1349 "TC filter IP protocol UDP\n"
1350 "TC filter source port\n"
1351 "TC filter source port\n"
1352 "TC filter destination port\n"
1353 "TC filter destination port\n"
1355 "TC rate number (bits/s) or rate string (suffixed with Bps or bit)\n")
1357 struct interface
*ifp
;
1361 ifp
= if_lookup_vrf_all(ifname
);
1364 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1368 p
= getprotobyname(ip_proto
);
1370 vty_out(vty
, "Unable to convert %s to proto id\n", ip_proto
);
1374 if (tc_getrate(ratestr
, &rate
) != 0) {
1375 vty_out(vty
, "Unable to convert %s to rate\n", ratestr
);
1379 if (sharp_zebra_send_tc_filter_rate(ifp
, src
, dst
, p
->p_proto
, src_port
,
1380 dst_port
, rate
) != 0)
1386 void sharp_vty_init(void)
1388 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
1389 install_element(ENABLE_NODE
, &install_routes_cmd
);
1390 install_element(ENABLE_NODE
, &install_seg6_routes_cmd
);
1391 install_element(ENABLE_NODE
, &install_seg6local_routes_cmd
);
1392 install_element(ENABLE_NODE
, &remove_routes_cmd
);
1393 install_element(ENABLE_NODE
, &vrf_label_cmd
);
1394 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
1395 install_element(ENABLE_NODE
, &watch_redistribute_cmd
);
1396 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
1397 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
1398 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
1399 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
1400 install_element(ENABLE_NODE
, &logpump_cmd
);
1401 install_element(ENABLE_NODE
, &create_session_cmd
);
1402 install_element(ENABLE_NODE
, &remove_session_cmd
);
1403 install_element(ENABLE_NODE
, &send_opaque_cmd
);
1404 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
1405 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
1406 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
1407 install_element(ENABLE_NODE
, &import_te_cmd
);
1409 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);
1410 install_element(ENABLE_NODE
, &show_sharp_ted_cmd
);
1411 install_element(ENABLE_NODE
, &show_sharp_cspf_cmd
);
1413 install_element(ENABLE_NODE
, &sharp_srv6_manager_get_locator_chunk_cmd
);
1414 install_element(ENABLE_NODE
,
1415 &sharp_srv6_manager_release_locator_chunk_cmd
);
1416 install_element(ENABLE_NODE
, &show_sharp_segment_routing_srv6_cmd
);
1418 install_element(ENABLE_NODE
, &sharp_interface_protodown_cmd
);
1419 install_element(ENABLE_NODE
, &no_sharp_interface_protodown_cmd
);
1421 install_element(ENABLE_NODE
, &tc_filter_rate_cmd
);