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"
32 #include "link_state.h"
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"
42 DEFINE_MTYPE_STATIC(SHARPD
, SRV6_LOCATOR
, "SRv6 Locator");
44 DEFPY(watch_redistribute
, watch_redistribute_cmd
,
45 "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD
,
46 "Sharp routing Protocol\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
)
57 vrf_name
= VRF_DEFAULT_NAME
;
58 vrf
= vrf_lookup_by_name(vrf_name
);
60 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
65 source
= proto_redistnum(AFI_IP
, argv
[argc
-1]->text
);
66 sharp_redistribute_vrf(vrf
, source
);
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"
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")
88 vrf_name
= VRF_DEFAULT_NAME
;
89 vrf
= vrf_lookup_by_name(vrf_name
);
91 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
96 memset(&p
, 0, sizeof(p
));
101 memcpy(&p
.u
.prefix6
, &nhop
, 16);
105 p
= *(const struct prefix
*)inhop
;
108 sharp_nh_tracker_get(&p
);
109 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
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")
132 vrf_name
= VRF_DEFAULT_NAME
;
133 vrf
= vrf_lookup_by_name(vrf_name
);
135 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
140 memset(&p
, 0, sizeof(p
));
150 p
= *(const struct prefix
*)inhop
;
153 sharp_nh_tracker_get(&p
);
154 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
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")
167 sharp_nh_tracker_dump(vty
);
172 DEFPY (install_routes_data_dump
,
173 install_routes_data_dump_cmd
,
175 "Sharp routing Protocol\n"
176 "Data about what is going on\n"
177 "Route Install/Removal Information\n")
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
);
189 DEFPY (install_routes
,
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"
215 "Should we repeat this command\n"
216 "How many times to repeat this command\n"
217 "What opaque data to send down\n"
221 struct prefix prefix
;
225 sg
.r
.total_routes
= routes
;
226 sg
.r
.installed_routes
= 0;
229 sg
.r
.repeat
= rpt
* 2;
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
));
240 if (start4
.s_addr
!= INADDR_ANY
) {
241 prefix
.family
= AF_INET
;
242 prefix
.prefixlen
= 32;
243 prefix
.u
.prefix4
= start4
;
245 prefix
.family
= AF_INET6
;
246 prefix
.prefixlen
= 128;
247 prefix
.u
.prefix6
= start6
;
249 sg
.r
.orig_prefix
= prefix
;
252 vrf_name
= VRF_DEFAULT_NAME
;
254 vrf
= vrf_lookup_by_name(vrf_name
);
256 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
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");
268 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
271 "Specified Nexthop Group: %s does not exist\n",
276 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
278 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
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
);
286 vty_out(vty
, "%% Backup group %s not found for group %s\n",
287 nhgc
->backup_list_name
,
292 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
293 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
296 if (nexthop4
.s_addr
!= INADDR_ANY
) {
297 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
298 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
300 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
301 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
304 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
305 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
308 /* Use single backup nexthop if specified */
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;
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
;
319 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
320 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
323 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
324 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
328 strlcpy(sg
.r
.opaque
, opaque
, ZAPI_MESSAGE_OPAQUE_LENGTH
);
330 sg
.r
.opaque
[0] = '\0';
332 sg
.r
.inst
= instance
;
333 sg
.r
.vrf_id
= vrf
->vrf_id
;
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
);
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"
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")
364 struct prefix prefix
;
365 uint32_t route_flags
= 0;
367 sg
.r
.total_routes
= routes
;
368 sg
.r
.installed_routes
= 0;
371 sg
.r
.repeat
= rpt
* 2;
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';
384 if (start4
.s_addr
!= INADDR_ANY
) {
385 prefix
.family
= AF_INET
;
386 prefix
.prefixlen
= 32;
387 prefix
.u
.prefix4
= start4
;
389 prefix
.family
= AF_INET6
;
390 prefix
.prefixlen
= 128;
391 prefix
.u
.prefix6
= start6
;
393 sg
.r
.orig_prefix
= prefix
;
396 vrf_name
= VRF_DEFAULT_NAME
;
398 vrf
= vrf_lookup_by_name(vrf_name
);
400 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
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
);
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
);
419 DEFPY (install_seg6local_routes
,
420 install_seg6local_routes_cmd
,
421 "sharp install seg6local-routes [vrf NAME$vrf_name]\
423 nexthop-seg6local NAME$seg6l_oif\
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")
452 uint32_t route_flags
= 0;
453 struct seg6local_context ctx
= {};
454 enum seg6local_action_t action
;
456 sg
.r
.total_routes
= routes
;
457 sg
.r
.installed_routes
= 0;
460 sg
.r
.repeat
= rpt
* 2;
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';
471 sg
.r
.orig_prefix
.family
= AF_INET6
;
472 sg
.r
.orig_prefix
.prefixlen
= 128;
473 sg
.r
.orig_prefix
.u
.prefix6
= start6
;
476 vrf_name
= VRF_DEFAULT_NAME
;
478 vrf
= vrf_lookup_by_name(vrf_name
);
480 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
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
;
498 action
= ZEBRA_SEG6_LOCAL_ACTION_END
;
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
);
507 sg
.r
.vrf_id
= vrf
->vrf_id
;
508 sharp_install_routes_helper(&sg
.r
.orig_prefix
, sg
.r
.vrf_id
, sg
.r
.inst
,
510 &sg
.r
.backup_nhop_group
, routes
,
511 route_flags
, sg
.r
.opaque
);
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"
523 "The label to use, 0 specifies remove the label installed from previous\n"
524 "Specified range to use\n")
527 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
529 if (strcmp(vrf_name
, "default") == 0)
530 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
532 vrf
= vrf_lookup_by_name(vrf_name
);
535 vty_out(vty
, "Unable to find vrf you silly head");
536 return CMD_WARNING_CONFIG_FAILED
;
540 label
= MPLS_LABEL_NONE
;
542 vrf_label_add(vrf
->vrf_id
, afi
, label
);
546 DEFPY (remove_routes
,
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"
552 "The vrf we would like to remove from if non-default\n"
553 "The NAME of the vrf\n"
556 "Routes to uninstall\n"
558 "Value of instance\n")
561 struct prefix prefix
;
563 sg
.r
.total_routes
= routes
;
564 sg
.r
.removed_routes
= 0;
567 memset(&prefix
, 0, sizeof(prefix
));
569 if (start4
.s_addr
!= INADDR_ANY
) {
570 prefix
.family
= AF_INET
;
571 prefix
.prefixlen
= 32;
572 prefix
.u
.prefix4
= start4
;
574 prefix
.family
= AF_INET6
;
575 prefix
.prefixlen
= 128;
576 prefix
.u
.prefix6
= start6
;
579 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
581 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
582 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
586 sg
.r
.inst
= instance
;
587 sg
.r
.vrf_id
= vrf
->vrf_id
;
589 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
595 DEFUN_NOSH (show_debugging_sharpd
,
596 show_debugging_sharpd_cmd
,
597 "show debugging [sharp]",
600 "Sharp Information\n")
602 vty_out(vty
, "Sharp debugging status:\n");
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"
615 "The ingress label to use\n"
616 "Use nexthops from a nexthop-group\n"
617 "The nexthop-group name\n"
619 "The v4 prefix to label\n"
620 FRR_IP_REDIST_HELP_STR_ZEBRA
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
= {};
631 update_p
= (update
!= NULL
);
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
;
639 type
= proto_redistnum(AFI_IP
, type_str
);
641 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
644 } else if (pfx
->family
> 0 || type_str
) {
645 vty_out(vty
, "%% Must supply both prefix and type\n");
649 nhgc
= nhgc_find(nhgname
);
651 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
656 if (nhgc
->nhg
.nexthop
== NULL
) {
657 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
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
);
667 "%% Backup group %s not found for group %s\n",
668 nhgc
->backup_list_name
,
672 backup_nhg
= &(backup_nhgc
->nhg
);
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)
681 vty_out(vty
, "%% LSP install failed!\n");
686 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
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"
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
704 struct nexthop_group_cmd
*nhgc
= NULL
;
705 struct prefix p
= {};
707 struct nexthop_group
*nhg
= NULL
;
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
;
715 type
= proto_redistnum(AFI_IP
, type_str
);
717 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
720 } else if (pfx
->family
> 0 || type_str
) {
721 vty_out(vty
, "%% Must supply both prefix and type\n");
726 nhgc
= nhgc_find(nhgname
);
728 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
733 if (nhgc
->nhg
.nexthop
== NULL
) {
734 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
741 if (sharp_install_lsps_helper(false /*!install*/, false,
742 pfx
->family
> 0 ? &p
: NULL
,
743 type
, instance
, inlabel
, nhg
, NULL
) == 0)
746 vty_out(vty
, "%% LSP remove failed!\n");
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")
763 sharp_logpump_run(vty
, duration
, frequency
, burst
);
767 DEFPY (create_session
,
769 "sharp create session (1-1024)",
770 "Sharp Routing Protocol\n"
772 "Create a test session\n"
775 if (sharp_zclient_create(session
) != 0) {
776 vty_out(vty
, "%% Client session error\n");
783 DEFPY (remove_session
,
785 "sharp remove session (1-1024)",
786 "Sharp Routing Protocol\n"
788 "Remove a test session\n"
791 sharp_zclient_delete(session
);
797 "sharp send opaque type (1-255) (1-1000)$count",
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")
805 sharp_opaque_send(type
, 0, 0, 0, count
);
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",
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
825 "Number of messages to send\n")
829 proto
= proto_redistnum(AFI_IP
, proto_str
);
831 sharp_opaque_send(type
, proto
, instance
, session
, count
);
836 DEFPY (send_opaque_reg
,
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)",
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
851 "Opaque sub-type code\n"
852 "Opaque sub-type code\n")
856 proto
= proto_redistnum(AFI_IP
, proto_str
);
858 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
862 DEFPY (neigh_discover
,
864 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
866 "Discover neighbours\n"
867 "Send an ARP/NDP request\n"
869 "v4 Destination address\n"
870 "v6 Destination address\n"
874 struct interface
*ifp
;
875 struct prefix prefix
;
877 memset(&prefix
, 0, sizeof(prefix
));
879 if (dst4
.s_addr
!= INADDR_ANY
) {
880 prefix
.family
= AF_INET
;
881 prefix
.prefixlen
= 32;
882 prefix
.u
.prefix4
= dst4
;
884 prefix
.family
= AF_INET6
;
885 prefix
.prefixlen
= 128;
886 prefix
.u
.prefix6
= dst6
;
889 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
891 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
892 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
896 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
898 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
902 sharp_zebra_send_arp(ifp
, &prefix
);
911 "Import Traffic Engineering\n")
913 sg
.ted
= ls_ted_new(1, "Sharp", 0);
914 sharp_zebra_register_te();
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",
923 "Segment-Routing IPv6\n"
924 "Get SRv6 locator-chunk\n"
925 "SRv6 Locator name\n")
928 struct listnode
*node
;
929 struct sharp_srv6_locator
*loc
;
930 struct sharp_srv6_locator
*loc_found
= NULL
;
932 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, node
, loc
)) {
933 if (strcmp(loc
->name
, locator_name
))
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
);
946 ret
= sharp_zebra_srv6_manager_get_locator_chunk(locator_name
);
948 return CMD_WARNING_CONFIG_FAILED
;
953 DEFUN (show_sharp_ted
,
955 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
958 "Traffic Engineering Database\n"
960 "MPLS-TE router ID (as an IP address)\n"
962 "MPLS-TE Edge ID (as an IP address)\n"
964 "MPLS-TE Subnet ID (as an IP prefix)\n"
969 struct in_addr ip_addr
;
971 struct ls_vertex
*vertex
;
972 struct ls_edge
*edge
;
973 struct ls_subnet
*subnet
;
975 bool verbose
= false;
976 bool uj
= use_json(argc
, argv
);
977 json_object
*json
= NULL
;
979 if (sg
.ted
== NULL
) {
980 vty_out(vty
, "MPLS-TE import is not enabled\n");
985 json
= json_object_new_object();
987 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
990 if (argv_find(argv
, argc
, "vertex", &idx
)) {
992 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
993 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
995 "Specified Router ID %s is invalid\n",
997 return CMD_WARNING_CONFIG_FAILED
;
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
);
1003 vty_out(vty
, "No vertex found for ID %pI4\n",
1011 ls_show_vertex(vertex
, vty
, json
, verbose
);
1013 ls_show_vertices(sg
.ted
, vty
, json
, verbose
);
1015 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1017 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1018 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
1020 "Specified Edge ID %s is invalid\n",
1022 return CMD_WARNING_CONFIG_FAILED
;
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
);
1028 vty_out(vty
, "No edge found for ID %pI4\n",
1036 ls_show_edge(edge
, vty
, json
, verbose
);
1038 ls_show_edges(sg
.ted
, vty
, json
, verbose
);
1040 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
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",
1046 return CMD_WARNING_CONFIG_FAILED
;
1048 /* Get the Subnet from the Link State Database */
1049 subnet
= ls_find_subnet(sg
.ted
, pref
);
1051 vty_out(vty
, "No subnet found for ID %pFX\n",
1059 ls_show_subnet(subnet
, vty
, json
, verbose
);
1061 ls_show_subnets(sg
.ted
, vty
, json
, verbose
);
1064 /* Show the complete TED */
1065 ls_show_ted(sg
.ted
, vty
, json
, verbose
);
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
);
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",
1082 "Segment-Routing IPv6\n"
1083 "Release SRv6 locator-chunk\n"
1084 "SRv6 Locator name\n")
1087 struct listnode
*loc_node
;
1088 struct sharp_srv6_locator
*loc
;
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
);
1099 ret
= sharp_zebra_srv6_manager_release_locator_chunk(locator_name
);
1101 return CMD_WARNING_CONFIG_FAILED
;
1106 DEFPY (show_sharp_segment_routing_srv6
,
1107 show_sharp_segment_routing_srv6_cmd
,
1108 "show sharp segment-routing srv6 [json]",
1112 "Segment-Routing IPv6\n"
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
;
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
,
1135 prefix2str(chunk
, str
, sizeof(str
));
1136 json_array_string_add(jo_chunks
, str
);
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
);
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
,
1149 prefix2str(chunk
, str
, sizeof(str
));
1150 vty_out(vty
, " %s\n", str
);
1159 void sharp_vty_init(void)
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
);
1182 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);
1183 install_element(ENABLE_NODE
, &show_sharp_ted_cmd
);
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
);