3 * Copyright (C) Cumulus Networks, Inc.
6 * This file is part of FRR.
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
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.
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
31 #include "nexthop_group.h"
33 #include "link_state.h"
36 #include "sharpd/sharp_globals.h"
37 #include "sharpd/sharp_zebra.h"
38 #include "sharpd/sharp_nht.h"
39 #include "sharpd/sharp_vty.h"
40 #ifndef VTYSH_EXTRACT_PL
41 #include "sharpd/sharp_vty_clippy.c"
44 DEFINE_MTYPE_STATIC(SHARPD
, SRV6_LOCATOR
, "SRv6 Locator");
46 DEFPY(watch_redistribute
, watch_redistribute_cmd
,
47 "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD
,
48 "Sharp routing Protocol\n"
50 "The vrf we would like to watch if non-default\n"
51 "The NAME of the vrf\n"
52 "Redistribute into Sharp\n"
53 FRR_REDIST_HELP_STR_SHARPD
)
59 vrf_name
= VRF_DEFAULT_NAME
;
60 vrf
= vrf_lookup_by_name(vrf_name
);
62 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
67 source
= proto_redistnum(AFI_IP
, argv
[argc
-1]->text
);
68 sharp_redistribute_vrf(vrf
, source
);
73 DEFPY(watch_nexthop_v6
, watch_nexthop_v6_cmd
,
74 "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
75 "Sharp routing Protocol\n"
77 "The vrf we would like to watch if non-default\n"
78 "The NAME of the vrf\n"
79 "Watch for nexthop changes\n"
80 "The v6 nexthop to signal for watching\n"
81 "Watch for import check changes\n"
82 "The v6 prefix to signal for watching\n"
83 "Should the route be connected\n")
90 vrf_name
= VRF_DEFAULT_NAME
;
91 vrf
= vrf_lookup_by_name(vrf_name
);
93 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
98 memset(&p
, 0, sizeof(p
));
102 p
.prefixlen
= IPV6_MAX_BITLEN
;
103 memcpy(&p
.u
.prefix6
, &nhop
, IPV6_MAX_BYTELEN
);
107 prefix_copy(&p
, inhop
);
110 sharp_nh_tracker_get(&p
);
111 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
117 DEFPY(watch_nexthop_v4
, watch_nexthop_v4_cmd
,
118 "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
119 "Sharp routing Protocol\n"
120 "Watch for changes\n"
121 "The vrf we would like to watch if non-default\n"
122 "The NAME of the vrf\n"
123 "Watch for nexthop changes\n"
124 "The v4 address to signal for watching\n"
125 "Watch for import check changes\n"
126 "The v4 prefix for import check to watch\n"
127 "Should the route be connected\n")
134 vrf_name
= VRF_DEFAULT_NAME
;
135 vrf
= vrf_lookup_by_name(vrf_name
);
137 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
142 memset(&p
, 0, sizeof(p
));
146 p
.prefixlen
= IPV4_MAX_BITLEN
;
152 prefix_copy(&p
, inhop
);
155 sharp_nh_tracker_get(&p
);
156 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
162 DEFPY(sharp_nht_data_dump
,
163 sharp_nht_data_dump_cmd
,
164 "sharp data nexthop",
165 "Sharp routing Protocol\n"
166 "Data about what is going on\n"
167 "Nexthop information\n")
169 sharp_nh_tracker_dump(vty
);
174 DEFPY (install_routes_data_dump
,
175 install_routes_data_dump_cmd
,
177 "Sharp routing Protocol\n"
178 "Data about what is going on\n"
179 "Route Install/Removal Information\n")
183 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
184 vty_out(vty
, "Prefix: %pFX Total: %u %u %u Time: %jd.%ld\n",
185 &sg
.r
.orig_prefix
, sg
.r
.total_routes
, sg
.r
.installed_routes
,
186 sg
.r
.removed_routes
, (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
191 DEFPY (install_routes
,
193 "sharp install routes [vrf NAME$vrf_name]\
194 <A.B.C.D$start4|X:X::X:X$start6>\
195 <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
196 nexthop-group NHGNAME$nexthop_group>\
197 [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
198 (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]",
199 "Sharp routing Protocol\n"
200 "install some routes\n"
201 "Routes to install\n"
202 "The vrf we would like to install into if non-default\n"
203 "The NAME of the vrf\n"
204 "v4 Address to start /32 generation at\n"
205 "v6 Address to start /32 generation at\n"
206 "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
207 "V4 Nexthop address to use\n"
208 "V6 Nexthop address to use\n"
209 "Nexthop-Group to use\n"
210 "The Name of the nexthop-group\n"
211 "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
212 "Backup V4 Nexthop address to use\n"
213 "Backup V6 Nexthop address to use\n"
214 "How many to create\n"
217 "Should we repeat this command\n"
218 "How many times to repeat this command\n"
219 "What opaque data to send down\n"
223 struct prefix prefix
;
227 sg
.r
.total_routes
= routes
;
228 sg
.r
.installed_routes
= 0;
231 sg
.r
.repeat
= rpt
* 2;
235 memset(&prefix
, 0, sizeof(prefix
));
236 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
237 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
238 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
239 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
240 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
241 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
242 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
244 if (start4
.s_addr
!= INADDR_ANY
) {
245 prefix
.family
= AF_INET
;
246 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
247 prefix
.u
.prefix4
= start4
;
249 prefix
.family
= AF_INET6
;
250 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
251 prefix
.u
.prefix6
= start6
;
253 sg
.r
.orig_prefix
= prefix
;
256 vrf_name
= VRF_DEFAULT_NAME
;
258 vrf
= vrf_lookup_by_name(vrf_name
);
260 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
265 /* Explicit backup not available with named nexthop-group */
266 if (backup
&& nexthop_group
) {
267 vty_out(vty
, "%% Invalid: cannot specify both nexthop-group and backup\n");
272 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
275 "Specified Nexthop Group: %s does not exist\n",
280 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
282 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
284 /* Use group's backup nexthop info if present */
285 if (nhgc
->backup_list_name
[0]) {
286 struct nexthop_group_cmd
*bnhgc
=
287 nhgc_find(nhgc
->backup_list_name
);
290 vty_out(vty
, "%% Backup group %s not found for group %s\n",
291 nhgc
->backup_list_name
,
296 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
297 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
300 if (nexthop4
.s_addr
!= INADDR_ANY
) {
301 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
302 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
304 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
305 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
308 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
309 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
312 /* Use single backup nexthop if specified */
314 /* Set flag and index in primary nexthop */
315 SET_FLAG(sg
.r
.nhop
.flags
, NEXTHOP_FLAG_HAS_BACKUP
);
316 sg
.r
.nhop
.backup_num
= 1;
317 sg
.r
.nhop
.backup_idx
[0] = 0;
319 if (backup_nexthop4
.s_addr
!= INADDR_ANY
) {
320 sg
.r
.backup_nhop
.gate
.ipv4
= backup_nexthop4
;
321 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV4
;
323 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
324 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
327 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
328 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
332 strlcpy(sg
.r
.opaque
, opaque
, ZAPI_MESSAGE_OPAQUE_LENGTH
);
334 sg
.r
.opaque
[0] = '\0';
336 sg
.r
.inst
= instance
;
337 sg
.r
.vrf_id
= vrf
->vrf_id
;
339 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, nhgid
,
340 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
341 rts
, 0, sg
.r
.opaque
);
346 DEFPY (install_seg6_routes
,
347 install_seg6_routes_cmd
,
348 "sharp install seg6-routes [vrf NAME$vrf_name]\
349 <A.B.C.D$start4|X:X::X:X$start6>\
350 nexthop-seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg\
351 (1-1000000)$routes [repeat (2-1000)$rpt]",
352 "Sharp routing Protocol\n"
353 "install some routes\n"
354 "Routes to install\n"
355 "The vrf we would like to install into if non-default\n"
356 "The NAME of the vrf\n"
357 "v4 Address to start /32 generation at\n"
358 "v6 Address to start /32 generation at\n"
359 "Nexthop-seg6 to use\n"
360 "V6 Nexthop address to use\n"
362 "Segment List to use\n"
363 "How many to create\n"
364 "Should we repeat this command\n"
365 "How many times to repeat this command\n")
368 struct prefix prefix
;
369 uint32_t route_flags
= 0;
371 sg
.r
.total_routes
= routes
;
372 sg
.r
.installed_routes
= 0;
375 sg
.r
.repeat
= rpt
* 2;
379 memset(&prefix
, 0, sizeof(prefix
));
380 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
381 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
382 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
383 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
384 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
385 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
386 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
387 sg
.r
.opaque
[0] = '\0';
390 if (start4
.s_addr
!= INADDR_ANY
) {
391 prefix
.family
= AF_INET
;
392 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
393 prefix
.u
.prefix4
= start4
;
395 prefix
.family
= AF_INET6
;
396 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
397 prefix
.u
.prefix6
= start6
;
399 sg
.r
.orig_prefix
= prefix
;
402 vrf_name
= VRF_DEFAULT_NAME
;
404 vrf
= vrf_lookup_by_name(vrf_name
);
406 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
411 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
412 sg
.r
.nhop
.gate
.ipv6
= seg6_nh6
;
413 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
414 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
415 nexthop_add_srv6_seg6(&sg
.r
.nhop
, &seg6_seg
);
417 sg
.r
.vrf_id
= vrf
->vrf_id
;
418 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, 0,
419 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
420 routes
, route_flags
, sg
.r
.opaque
);
425 DEFPY (install_seg6local_routes
,
426 install_seg6local_routes_cmd
,
427 "sharp install seg6local-routes [vrf NAME$vrf_name]\
429 nexthop-seg6local NAME$seg6l_oif\
431 End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
432 End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
433 End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
434 End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
435 End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table>\
436 (1-1000000)$routes [repeat (2-1000)$rpt]",
437 "Sharp routing Protocol\n"
438 "install some routes\n"
439 "Routes to install\n"
440 "The vrf we would like to install into if non-default\n"
441 "The NAME of the vrf\n"
442 "v6 Address to start /32 generation at\n"
443 "Nexthop-seg6local to use\n"
444 "Output device to use\n"
445 "SRv6 End function to use\n"
446 "SRv6 End.X function to use\n"
447 "V6 Nexthop address to use\n"
448 "SRv6 End.T function to use\n"
449 "Redirect table id to use\n"
450 "SRv6 End.DX4 function to use\n"
451 "V4 Nexthop address to use\n"
452 "SRv6 End.DT6 function to use\n"
453 "Redirect table id to use\n"
454 "SRv6 End.DT4 function to use\n"
455 "Redirect table id to use\n"
456 "How many to create\n"
457 "Should we repeat this command\n"
458 "How many times to repeat this command\n")
461 uint32_t route_flags
= 0;
462 struct seg6local_context ctx
= {};
463 enum seg6local_action_t action
;
465 sg
.r
.total_routes
= routes
;
466 sg
.r
.installed_routes
= 0;
469 sg
.r
.repeat
= rpt
* 2;
473 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
474 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
475 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
476 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
477 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
478 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
479 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
480 sg
.r
.opaque
[0] = '\0';
482 sg
.r
.orig_prefix
.family
= AF_INET6
;
483 sg
.r
.orig_prefix
.prefixlen
= 128;
484 sg
.r
.orig_prefix
.u
.prefix6
= start6
;
487 vrf_name
= VRF_DEFAULT_NAME
;
489 vrf
= vrf_lookup_by_name(vrf_name
);
491 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
497 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DX4
;
498 ctx
.nh4
= seg6l_enddx4_nh4
;
499 } else if (seg6l_endx
) {
500 action
= ZEBRA_SEG6_LOCAL_ACTION_END_X
;
501 ctx
.nh6
= seg6l_endx_nh6
;
502 } else if (seg6l_endt
) {
503 action
= ZEBRA_SEG6_LOCAL_ACTION_END_T
;
504 ctx
.table
= seg6l_endt_table
;
505 } else if (seg6l_enddt6
) {
506 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT6
;
507 ctx
.table
= seg6l_enddt6_table
;
508 } else if (seg6l_enddt4
) {
509 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT4
;
510 ctx
.table
= seg6l_enddt4_table
;
512 action
= ZEBRA_SEG6_LOCAL_ACTION_END
;
515 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
516 sg
.r
.nhop
.ifindex
= ifname2ifindex(seg6l_oif
, vrf
->vrf_id
);
517 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
518 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
519 nexthop_add_srv6_seg6local(&sg
.r
.nhop
, action
, &ctx
);
521 sg
.r
.vrf_id
= vrf
->vrf_id
;
522 sharp_install_routes_helper(&sg
.r
.orig_prefix
, sg
.r
.vrf_id
, sg
.r
.inst
,
524 &sg
.r
.backup_nhop_group
, routes
,
525 route_flags
, sg
.r
.opaque
);
530 DEFPY(vrf_label
, vrf_label_cmd
,
531 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
532 "Sharp Routing Protocol\n"
533 "Give a vrf a label\n"
534 "Pop and forward for IPv4\n"
535 "Pop and forward for IPv6\n"
537 "The label to use, 0 specifies remove the label installed from previous\n"
538 "Specified range to use\n")
541 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
543 if (strcmp(vrf_name
, "default") == 0)
544 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
546 vrf
= vrf_lookup_by_name(vrf_name
);
549 vty_out(vty
, "Unable to find vrf you silly head\n");
550 return CMD_WARNING_CONFIG_FAILED
;
554 label
= MPLS_LABEL_NONE
;
556 vrf_label_add(vrf
->vrf_id
, afi
, label
);
560 DEFPY (remove_routes
,
562 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
563 "Sharp Routing Protocol\n"
564 "Remove some routes\n"
566 "The vrf we would like to remove from if non-default\n"
567 "The NAME of the vrf\n"
570 "Routes to uninstall\n"
572 "Value of instance\n")
575 struct prefix prefix
;
577 sg
.r
.total_routes
= routes
;
578 sg
.r
.removed_routes
= 0;
581 memset(&prefix
, 0, sizeof(prefix
));
583 if (start4
.s_addr
!= INADDR_ANY
) {
584 prefix
.family
= AF_INET
;
585 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
586 prefix
.u
.prefix4
= start4
;
588 prefix
.family
= AF_INET6
;
589 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
590 prefix
.u
.prefix6
= start6
;
593 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
595 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
596 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
600 sg
.r
.inst
= instance
;
601 sg
.r
.vrf_id
= vrf
->vrf_id
;
603 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
609 DEFUN_NOSH (show_debugging_sharpd
,
610 show_debugging_sharpd_cmd
,
611 "show debugging [sharp]",
614 "Sharp Information\n")
616 vty_out(vty
, "Sharp debugging status:\n");
618 cmd_show_lib_debugs(vty
);
623 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
624 "sharp lsp [update]$update (0-100000)$inlabel\
625 nexthop-group NHGNAME$nhgname\
626 [prefix A.B.C.D/M$pfx\
627 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
628 "Sharp Routing Protocol\n"
631 "The ingress label to use\n"
632 "Use nexthops from a nexthop-group\n"
633 "The nexthop-group name\n"
635 "The v4 prefix to label\n"
636 FRR_IP_REDIST_HELP_STR_ZEBRA
640 struct nexthop_group_cmd
*nhgc
= NULL
;
641 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
642 struct nexthop_group
*backup_nhg
= NULL
;
643 struct prefix p
= {};
647 update_p
= (update
!= NULL
);
649 /* We're offered a v4 prefix */
650 if (pfx
->family
> 0 && type_str
) {
651 p
.family
= pfx
->family
;
652 p
.prefixlen
= pfx
->prefixlen
;
653 p
.u
.prefix4
= pfx
->prefix
;
655 type
= proto_redistnum(AFI_IP
, type_str
);
657 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
660 } else if (pfx
->family
> 0 || type_str
) {
661 vty_out(vty
, "%% Must supply both prefix and type\n");
665 nhgc
= nhgc_find(nhgname
);
667 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
672 if (nhgc
->nhg
.nexthop
== NULL
) {
673 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
677 /* Use group's backup nexthop info if present */
678 if (nhgc
->backup_list_name
[0]) {
679 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
683 "%% Backup group %s not found for group %s\n",
684 nhgc
->backup_list_name
,
688 backup_nhg
= &(backup_nhgc
->nhg
);
691 if (sharp_install_lsps_helper(true /*install*/, update_p
,
692 pfx
->family
> 0 ? &p
: NULL
,
693 type
, instance
, inlabel
,
694 &(nhgc
->nhg
), backup_nhg
) == 0)
697 vty_out(vty
, "%% LSP install failed!\n");
702 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
705 [nexthop-group NHGNAME$nhgname] \
706 [prefix A.B.C.D/M$pfx\
707 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
708 "Sharp Routing Protocol\n"
711 "The ingress label\n"
712 "Use nexthops from a nexthop-group\n"
713 "The nexthop-group name\n"
714 "Specify a v4 prefix\n"
715 "The v4 prefix to label\n"
716 FRR_IP_REDIST_HELP_STR_ZEBRA
720 struct nexthop_group_cmd
*nhgc
= NULL
;
721 struct prefix p
= {};
723 struct nexthop_group
*nhg
= NULL
;
725 /* We're offered a v4 prefix */
726 if (pfx
->family
> 0 && type_str
) {
727 p
.family
= pfx
->family
;
728 p
.prefixlen
= pfx
->prefixlen
;
729 p
.u
.prefix4
= pfx
->prefix
;
731 type
= proto_redistnum(AFI_IP
, type_str
);
733 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
736 } else if (pfx
->family
> 0 || type_str
) {
737 vty_out(vty
, "%% Must supply both prefix and type\n");
742 nhgc
= nhgc_find(nhgname
);
744 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
749 if (nhgc
->nhg
.nexthop
== NULL
) {
750 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
757 if (sharp_install_lsps_helper(false /*!install*/, false,
758 pfx
->family
> 0 ? &p
: NULL
,
759 type
, instance
, inlabel
, nhg
, NULL
) == 0)
762 vty_out(vty
, "%% LSP remove failed!\n");
769 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
770 "Sharp Routing Protocol\n"
771 "Generate bulk log messages for testing\n"
772 "Duration of run (s)\n"
773 "Duration of run (s)\n"
774 "Frequency of bursts (s^-1)\n"
775 "Frequency of bursts (s^-1)\n"
776 "Number of log messages per each burst\n"
777 "Number of log messages per each burst\n")
779 sharp_logpump_run(vty
, duration
, frequency
, burst
);
783 DEFPY (create_session
,
785 "sharp create session (1-1024)",
786 "Sharp Routing Protocol\n"
788 "Create a test session\n"
791 if (sharp_zclient_create(session
) != 0) {
792 vty_out(vty
, "%% Client session error\n");
799 DEFPY (remove_session
,
801 "sharp remove session (1-1024)",
802 "Sharp Routing Protocol\n"
804 "Remove a test session\n"
807 sharp_zclient_delete(session
);
813 "sharp send opaque type (1-255) (1-1000)$count",
815 "Send messages for testing\n"
816 "Send opaque messages\n"
817 "Type code to send\n"
818 "Type code to send\n"
819 "Number of messages to send\n")
821 sharp_opaque_send(type
, 0, 0, 0, count
);
825 DEFPY (send_opaque_unicast
,
826 send_opaque_unicast_cmd
,
827 "sharp send opaque unicast type (1-255) \
828 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
829 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
831 "Send messages for testing\n"
832 "Send opaque messages\n"
833 "Send unicast messages\n"
834 "Type code to send\n"
835 "Type code to send\n"
836 FRR_IP_REDIST_HELP_STR_ZEBRA
841 "Number of messages to send\n")
845 proto
= proto_redistnum(AFI_IP
, proto_str
);
847 sharp_opaque_send(type
, proto
, instance
, session
, count
);
852 DEFPY (send_opaque_reg
,
854 "sharp send opaque <reg$reg | unreg> \
855 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
856 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
858 "Send messages for testing\n"
859 "Send opaque messages\n"
860 "Send opaque registration\n"
861 "Send opaque unregistration\n"
862 FRR_IP_REDIST_HELP_STR_ZEBRA
867 "Opaque sub-type code\n"
868 "Opaque sub-type code\n")
872 proto
= proto_redistnum(AFI_IP
, proto_str
);
874 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
878 DEFPY (neigh_discover
,
880 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
882 "Discover neighbours\n"
883 "Send an ARP/NDP request\n"
885 "v4 Destination address\n"
886 "v6 Destination address\n"
890 struct interface
*ifp
;
891 struct prefix prefix
;
893 memset(&prefix
, 0, sizeof(prefix
));
895 if (dst4
.s_addr
!= INADDR_ANY
) {
896 prefix
.family
= AF_INET
;
897 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
898 prefix
.u
.prefix4
= dst4
;
900 prefix
.family
= AF_INET6
;
901 prefix
.prefixlen
= 128;
902 prefix
.u
.prefix6
= dst6
;
905 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
907 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
908 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
912 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
914 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
918 sharp_zebra_send_arp(ifp
, &prefix
);
927 "Import Traffic Engineering\n")
929 sg
.ted
= ls_ted_new(1, "Sharp", 0);
930 sharp_zebra_register_te();
935 static void sharp_srv6_locator_chunk_free(struct prefix_ipv6
*chunk
)
937 prefix_ipv6_free((struct prefix_ipv6
**)&chunk
);
940 DEFPY (sharp_srv6_manager_get_locator_chunk
,
941 sharp_srv6_manager_get_locator_chunk_cmd
,
942 "sharp srv6-manager get-locator-chunk NAME$locator_name",
944 "Segment-Routing IPv6\n"
945 "Get SRv6 locator-chunk\n"
946 "SRv6 Locator name\n")
949 struct listnode
*node
;
950 struct sharp_srv6_locator
*loc
;
951 struct sharp_srv6_locator
*loc_found
= NULL
;
953 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, node
, loc
)) {
954 if (strcmp(loc
->name
, locator_name
))
960 loc
= XCALLOC(MTYPE_SRV6_LOCATOR
,
961 sizeof(struct sharp_srv6_locator
));
962 loc
->chunks
= list_new();
964 (void (*)(void *))sharp_srv6_locator_chunk_free
;
965 snprintf(loc
->name
, SRV6_LOCNAME_SIZE
, "%s", locator_name
);
966 listnode_add(sg
.srv6_locators
, loc
);
969 ret
= sharp_zebra_srv6_manager_get_locator_chunk(locator_name
);
971 return CMD_WARNING_CONFIG_FAILED
;
976 DEFUN (show_sharp_ted
,
978 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
981 "Traffic Engineering Database\n"
983 "MPLS-TE router ID (as an IP address)\n"
985 "MPLS-TE Edge ID (as an IP address)\n"
987 "MPLS-TE Subnet ID (as an IP prefix)\n"
992 struct in_addr ip_addr
;
994 struct ls_vertex
*vertex
;
995 struct ls_edge
*edge
;
996 struct ls_subnet
*subnet
;
998 bool verbose
= false;
999 bool uj
= use_json(argc
, argv
);
1000 json_object
*json
= NULL
;
1002 if (sg
.ted
== NULL
) {
1003 vty_out(vty
, "MPLS-TE import is not enabled\n");
1008 json
= json_object_new_object();
1010 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
1013 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1015 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1016 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
1018 "Specified Router ID %s is invalid\n",
1019 argv
[idx
+ 1]->arg
);
1020 return CMD_WARNING_CONFIG_FAILED
;
1022 /* Get the Vertex from the Link State Database */
1023 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1024 vertex
= ls_find_vertex_by_key(sg
.ted
, key
);
1026 vty_out(vty
, "No vertex found for ID %pI4\n",
1034 ls_show_vertex(vertex
, vty
, json
, verbose
);
1036 ls_show_vertices(sg
.ted
, vty
, json
, verbose
);
1038 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1040 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1041 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
1043 "Specified Edge ID %s is invalid\n",
1045 return CMD_WARNING_CONFIG_FAILED
;
1047 /* Get the Edge from the Link State Database */
1048 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1049 edge
= ls_find_edge_by_key(sg
.ted
, key
);
1051 vty_out(vty
, "No edge found for ID %pI4\n",
1059 ls_show_edge(edge
, vty
, json
, verbose
);
1061 ls_show_edges(sg
.ted
, vty
, json
, verbose
);
1063 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1065 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1066 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1067 vty_out(vty
, "Invalid prefix format %s\n",
1069 return CMD_WARNING_CONFIG_FAILED
;
1071 /* Get the Subnet from the Link State Database */
1072 subnet
= ls_find_subnet(sg
.ted
, pref
);
1074 vty_out(vty
, "No subnet found for ID %pFX\n",
1082 ls_show_subnet(subnet
, vty
, json
, verbose
);
1084 ls_show_subnets(sg
.ted
, vty
, json
, verbose
);
1087 /* Show the complete TED */
1088 ls_show_ted(sg
.ted
, vty
, json
, verbose
);
1092 vty_json(vty
, json
);
1097 DEFPY (sharp_srv6_manager_release_locator_chunk
,
1098 sharp_srv6_manager_release_locator_chunk_cmd
,
1099 "sharp srv6-manager release-locator-chunk NAME$locator_name",
1101 "Segment-Routing IPv6\n"
1102 "Release SRv6 locator-chunk\n"
1103 "SRv6 Locator name\n")
1106 struct listnode
*loc_node
;
1107 struct sharp_srv6_locator
*loc
;
1109 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1110 if (!strcmp(loc
->name
, locator_name
)) {
1111 list_delete_all_node(loc
->chunks
);
1112 list_delete(&loc
->chunks
);
1113 listnode_delete(sg
.srv6_locators
, loc
);
1114 XFREE(MTYPE_SRV6_LOCATOR
, loc
);
1119 ret
= sharp_zebra_srv6_manager_release_locator_chunk(locator_name
);
1121 return CMD_WARNING_CONFIG_FAILED
;
1126 DEFPY (show_sharp_segment_routing_srv6
,
1127 show_sharp_segment_routing_srv6_cmd
,
1128 "show sharp segment-routing srv6 [json]",
1132 "Segment-Routing IPv6\n"
1136 struct listnode
*loc_node
;
1137 struct listnode
*chunk_node
;
1138 struct sharp_srv6_locator
*loc
;
1139 struct prefix_ipv6
*chunk
;
1140 bool uj
= use_json(argc
, argv
);
1141 json_object
*jo_locs
= NULL
;
1142 json_object
*jo_loc
= NULL
;
1143 json_object
*jo_chunks
= NULL
;
1146 jo_locs
= json_object_new_array();
1147 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1148 jo_loc
= json_object_new_object();
1149 json_object_array_add(jo_locs
, jo_loc
);
1150 json_object_string_add(jo_loc
, "name", loc
->name
);
1151 jo_chunks
= json_object_new_array();
1152 json_object_object_add(jo_loc
, "chunks", jo_chunks
);
1153 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1155 prefix2str(chunk
, str
, sizeof(str
));
1156 json_array_string_add(jo_chunks
, str
);
1160 vty_json(vty
, jo_locs
);
1162 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1163 vty_out(vty
, "Locator %s has %d prefix chunks\n",
1164 loc
->name
, listcount(loc
->chunks
));
1165 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1167 prefix2str(chunk
, str
, sizeof(str
));
1168 vty_out(vty
, " %s\n", str
);
1177 DEFPY (show_sharp_cspf
,
1178 show_sharp_cspf_cmd
,
1179 "show sharp cspf source <A.B.C.D$src4|X:X::X:X$src6> \
1180 destination <A.B.C.D$dst4|X:X::X:X$dst6> \
1181 <metric|te-metric|delay> (0-16777215)$cost \
1182 [rsv-bw (0-7)$cos BANDWIDTH$bw]",
1185 "Constraint Shortest Path First path computation\n"
1186 "Source of the path\n"
1187 "IPv4 Source address in dot decimal A.B.C.D\n"
1188 "IPv6 Source address as X:X:X:X\n"
1189 "Destination of the path\n"
1190 "IPv4 Destination address in dot decimal A.B.C.D\n"
1191 "IPv6 Destination address as X:X:X:X\n"
1193 "Maximum TE Metric\n"
1195 "Value of Maximum cost\n"
1196 "Reserved Bandwidth of this path\n"
1197 "Class of Service or Priority level\n"
1198 "Bytes/second (IEEE floating point format)\n")
1202 struct constraints csts
;
1203 struct c_path
*path
;
1204 struct listnode
*node
;
1205 struct ls_edge
*edge
;
1208 if (sg
.ted
== NULL
) {
1209 vty_out(vty
, "MPLS-TE import is not enabled\n");
1213 if ((src4
.s_addr
!= INADDR_ANY
&& dst4
.s_addr
== INADDR_ANY
) ||
1214 (src4
.s_addr
== INADDR_ANY
&& dst4
.s_addr
!= INADDR_ANY
)) {
1215 vty_out(vty
, "Don't mix IPv4 and IPv6 addresses\n");
1220 memset(&csts
, 0, sizeof(struct constraints
));
1221 if (argv_find(argv
, argc
, "metric", &idx
)) {
1222 csts
.ctype
= CSPF_METRIC
;
1226 if (argv_find(argv
, argc
, "te-metric", &idx
)) {
1227 csts
.ctype
= CSPF_TE_METRIC
;
1231 if (argv_find(argv
, argc
, "delay", &idx
)) {
1232 csts
.ctype
= CSPF_DELAY
;
1236 if (sscanf(bw
, "%g", &csts
.bw
) != 1) {
1237 vty_out(vty
, "Bandwidth constraints: fscanf: %s\n",
1238 safe_strerror(errno
));
1239 return CMD_WARNING_CONFIG_FAILED
;
1244 /* Initialize and call point-to-point Path computation */
1245 if (src4
.s_addr
!= INADDR_ANY
)
1246 algo
= cspf_init_v4(NULL
, sg
.ted
, src4
, dst4
, &csts
);
1248 algo
= cspf_init_v6(NULL
, sg
.ted
, src6
, dst6
, &csts
);
1249 path
= compute_p2p_path(algo
, sg
.ted
);
1253 vty_out(vty
, "Path computation failed without error\n");
1256 if (path
->status
!= SUCCESS
) {
1257 vty_out(vty
, "Path computation failed: %d\n", path
->status
);
1261 vty_out(vty
, "Path computation success\n");
1262 vty_out(vty
, "\tCost: %d\n", path
->weight
);
1263 vty_out(vty
, "\tEdges:");
1264 for (ALL_LIST_ELEMENTS_RO(path
->edges
, node
, edge
)) {
1265 if (src4
.s_addr
!= INADDR_ANY
)
1266 vty_out(vty
, " %pI4",
1267 &edge
->attributes
->standard
.remote
);
1269 vty_out(vty
, " %pI6",
1270 &edge
->attributes
->standard
.remote6
);
1277 static struct interface
*if_lookup_vrf_all(const char *ifname
)
1279 struct interface
*ifp
;
1282 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1283 ifp
= if_lookup_by_name(ifname
, vrf
->vrf_id
);
1291 DEFPY (sharp_interface_protodown
,
1292 sharp_interface_protodown_cmd
,
1293 "sharp interface IFNAME$ifname protodown",
1297 "Set interface protodown\n")
1299 struct interface
*ifp
;
1301 ifp
= if_lookup_vrf_all(ifname
);
1304 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1308 if (sharp_zebra_send_interface_protodown(ifp
, true) != 0)
1314 DEFPY (no_sharp_interface_protodown
,
1315 no_sharp_interface_protodown_cmd
,
1316 "no sharp interface IFNAME$ifname protodown",
1321 "Set interface protodown\n")
1323 struct interface
*ifp
;
1325 ifp
= if_lookup_vrf_all(ifname
);
1328 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1332 if (sharp_zebra_send_interface_protodown(ifp
, false) != 0)
1338 void sharp_vty_init(void)
1340 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
1341 install_element(ENABLE_NODE
, &install_routes_cmd
);
1342 install_element(ENABLE_NODE
, &install_seg6_routes_cmd
);
1343 install_element(ENABLE_NODE
, &install_seg6local_routes_cmd
);
1344 install_element(ENABLE_NODE
, &remove_routes_cmd
);
1345 install_element(ENABLE_NODE
, &vrf_label_cmd
);
1346 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
1347 install_element(ENABLE_NODE
, &watch_redistribute_cmd
);
1348 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
1349 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
1350 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
1351 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
1352 install_element(ENABLE_NODE
, &logpump_cmd
);
1353 install_element(ENABLE_NODE
, &create_session_cmd
);
1354 install_element(ENABLE_NODE
, &remove_session_cmd
);
1355 install_element(ENABLE_NODE
, &send_opaque_cmd
);
1356 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
1357 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
1358 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
1359 install_element(ENABLE_NODE
, &import_te_cmd
);
1361 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);
1362 install_element(ENABLE_NODE
, &show_sharp_ted_cmd
);
1363 install_element(ENABLE_NODE
, &show_sharp_cspf_cmd
);
1365 install_element(ENABLE_NODE
, &sharp_srv6_manager_get_locator_chunk_cmd
);
1366 install_element(ENABLE_NODE
,
1367 &sharp_srv6_manager_release_locator_chunk_cmd
);
1368 install_element(ENABLE_NODE
, &show_sharp_segment_routing_srv6_cmd
);
1370 install_element(ENABLE_NODE
, &sharp_interface_protodown_cmd
);
1371 install_element(ENABLE_NODE
, &no_sharp_interface_protodown_cmd
);