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 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
238 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
239 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
240 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
242 if (start4
.s_addr
!= INADDR_ANY
) {
243 prefix
.family
= AF_INET
;
244 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
245 prefix
.u
.prefix4
= start4
;
247 prefix
.family
= AF_INET6
;
248 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
249 prefix
.u
.prefix6
= start6
;
251 sg
.r
.orig_prefix
= prefix
;
254 vrf_name
= VRF_DEFAULT_NAME
;
256 vrf
= vrf_lookup_by_name(vrf_name
);
258 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
263 /* Explicit backup not available with named nexthop-group */
264 if (backup
&& nexthop_group
) {
265 vty_out(vty
, "%% Invalid: cannot specify both nexthop-group and backup\n");
270 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
273 "Specified Nexthop Group: %s does not exist\n",
278 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
280 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
282 /* Use group's backup nexthop info if present */
283 if (nhgc
->backup_list_name
[0]) {
284 struct nexthop_group_cmd
*bnhgc
=
285 nhgc_find(nhgc
->backup_list_name
);
288 vty_out(vty
, "%% Backup group %s not found for group %s\n",
289 nhgc
->backup_list_name
,
294 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
295 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
298 if (nexthop4
.s_addr
!= INADDR_ANY
) {
299 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
300 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
302 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
303 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
306 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
307 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
310 /* Use single backup nexthop if specified */
312 /* Set flag and index in primary nexthop */
313 SET_FLAG(sg
.r
.nhop
.flags
, NEXTHOP_FLAG_HAS_BACKUP
);
314 sg
.r
.nhop
.backup_num
= 1;
315 sg
.r
.nhop
.backup_idx
[0] = 0;
317 if (backup_nexthop4
.s_addr
!= INADDR_ANY
) {
318 sg
.r
.backup_nhop
.gate
.ipv4
= backup_nexthop4
;
319 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV4
;
321 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
322 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
325 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
326 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
330 strlcpy(sg
.r
.opaque
, opaque
, ZAPI_MESSAGE_OPAQUE_LENGTH
);
332 sg
.r
.opaque
[0] = '\0';
334 sg
.r
.inst
= instance
;
335 sg
.r
.vrf_id
= vrf
->vrf_id
;
337 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, nhgid
,
338 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
339 rts
, 0, sg
.r
.opaque
);
344 DEFPY (install_seg6_routes
,
345 install_seg6_routes_cmd
,
346 "sharp install seg6-routes [vrf NAME$vrf_name]\
347 <A.B.C.D$start4|X:X::X:X$start6>\
348 nexthop-seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg\
349 (1-1000000)$routes [repeat (2-1000)$rpt]",
350 "Sharp routing Protocol\n"
351 "install some routes\n"
352 "Routes to install\n"
353 "The vrf we would like to install into if non-default\n"
354 "The NAME of the vrf\n"
355 "v4 Address to start /32 generation at\n"
356 "v6 Address to start /32 generation at\n"
357 "Nexthop-seg6 to use\n"
358 "V6 Nexthop address to use\n"
360 "Segment List to use\n"
361 "How many to create\n"
362 "Should we repeat this command\n"
363 "How many times to repeat this command\n")
366 struct prefix prefix
;
367 uint32_t route_flags
= 0;
369 sg
.r
.total_routes
= routes
;
370 sg
.r
.installed_routes
= 0;
373 sg
.r
.repeat
= rpt
* 2;
377 memset(&prefix
, 0, sizeof(prefix
));
378 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
379 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
380 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
381 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
382 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
383 sg
.r
.opaque
[0] = '\0';
386 if (start4
.s_addr
!= INADDR_ANY
) {
387 prefix
.family
= AF_INET
;
388 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
389 prefix
.u
.prefix4
= start4
;
391 prefix
.family
= AF_INET6
;
392 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
393 prefix
.u
.prefix6
= start6
;
395 sg
.r
.orig_prefix
= prefix
;
398 vrf_name
= VRF_DEFAULT_NAME
;
400 vrf
= vrf_lookup_by_name(vrf_name
);
402 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
407 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
408 sg
.r
.nhop
.gate
.ipv6
= seg6_nh6
;
409 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
410 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
411 nexthop_add_srv6_seg6(&sg
.r
.nhop
, &seg6_seg
);
413 sg
.r
.vrf_id
= vrf
->vrf_id
;
414 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, 0,
415 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
416 routes
, route_flags
, sg
.r
.opaque
);
421 DEFPY (install_seg6local_routes
,
422 install_seg6local_routes_cmd
,
423 "sharp install seg6local-routes [vrf NAME$vrf_name]\
425 nexthop-seg6local NAME$seg6l_oif\
427 End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
428 End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
429 End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
430 End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
431 End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table>\
432 (1-1000000)$routes [repeat (2-1000)$rpt]",
433 "Sharp routing Protocol\n"
434 "install some routes\n"
435 "Routes to install\n"
436 "The vrf we would like to install into if non-default\n"
437 "The NAME of the vrf\n"
438 "v6 Address to start /32 generation at\n"
439 "Nexthop-seg6local to use\n"
440 "Output device to use\n"
441 "SRv6 End function to use\n"
442 "SRv6 End.X function to use\n"
443 "V6 Nexthop address to use\n"
444 "SRv6 End.T function to use\n"
445 "Redirect table id to use\n"
446 "SRv6 End.DX4 function to use\n"
447 "V4 Nexthop address to use\n"
448 "SRv6 End.DT6 function to use\n"
449 "Redirect table id to use\n"
450 "SRv6 End.DT4 function to use\n"
451 "Redirect table id to use\n"
452 "How many to create\n"
453 "Should we repeat this command\n"
454 "How many times to repeat this command\n")
457 uint32_t route_flags
= 0;
458 struct seg6local_context ctx
= {};
459 enum seg6local_action_t action
;
461 sg
.r
.total_routes
= routes
;
462 sg
.r
.installed_routes
= 0;
465 sg
.r
.repeat
= rpt
* 2;
469 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
470 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
471 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
472 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
473 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
474 sg
.r
.opaque
[0] = '\0';
476 sg
.r
.orig_prefix
.family
= AF_INET6
;
477 sg
.r
.orig_prefix
.prefixlen
= 128;
478 sg
.r
.orig_prefix
.u
.prefix6
= start6
;
481 vrf_name
= VRF_DEFAULT_NAME
;
483 vrf
= vrf_lookup_by_name(vrf_name
);
485 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
491 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DX4
;
492 ctx
.nh4
= seg6l_enddx4_nh4
;
493 } else if (seg6l_endx
) {
494 action
= ZEBRA_SEG6_LOCAL_ACTION_END_X
;
495 ctx
.nh6
= seg6l_endx_nh6
;
496 } else if (seg6l_endt
) {
497 action
= ZEBRA_SEG6_LOCAL_ACTION_END_T
;
498 ctx
.table
= seg6l_endt_table
;
499 } else if (seg6l_enddt6
) {
500 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT6
;
501 ctx
.table
= seg6l_enddt6_table
;
502 } else if (seg6l_enddt4
) {
503 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT4
;
504 ctx
.table
= seg6l_enddt4_table
;
506 action
= ZEBRA_SEG6_LOCAL_ACTION_END
;
509 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
510 sg
.r
.nhop
.ifindex
= ifname2ifindex(seg6l_oif
, vrf
->vrf_id
);
511 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
512 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
513 nexthop_add_srv6_seg6local(&sg
.r
.nhop
, action
, &ctx
);
515 sg
.r
.vrf_id
= vrf
->vrf_id
;
516 sharp_install_routes_helper(&sg
.r
.orig_prefix
, sg
.r
.vrf_id
, sg
.r
.inst
,
518 &sg
.r
.backup_nhop_group
, routes
,
519 route_flags
, sg
.r
.opaque
);
524 DEFPY(vrf_label
, vrf_label_cmd
,
525 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
526 "Sharp Routing Protocol\n"
527 "Give a vrf a label\n"
528 "Pop and forward for IPv4\n"
529 "Pop and forward for IPv6\n"
531 "The label to use, 0 specifies remove the label installed from previous\n"
532 "Specified range to use\n")
535 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
537 if (strcmp(vrf_name
, "default") == 0)
538 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
540 vrf
= vrf_lookup_by_name(vrf_name
);
543 vty_out(vty
, "Unable to find vrf you silly head\n");
544 return CMD_WARNING_CONFIG_FAILED
;
548 label
= MPLS_LABEL_NONE
;
550 vrf_label_add(vrf
->vrf_id
, afi
, label
);
554 DEFPY (remove_routes
,
556 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
557 "Sharp Routing Protocol\n"
558 "Remove some routes\n"
560 "The vrf we would like to remove from if non-default\n"
561 "The NAME of the vrf\n"
564 "Routes to uninstall\n"
566 "Value of instance\n")
569 struct prefix prefix
;
571 sg
.r
.total_routes
= routes
;
572 sg
.r
.removed_routes
= 0;
575 memset(&prefix
, 0, sizeof(prefix
));
577 if (start4
.s_addr
!= INADDR_ANY
) {
578 prefix
.family
= AF_INET
;
579 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
580 prefix
.u
.prefix4
= start4
;
582 prefix
.family
= AF_INET6
;
583 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
584 prefix
.u
.prefix6
= start6
;
587 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
589 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
590 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
594 sg
.r
.inst
= instance
;
595 sg
.r
.vrf_id
= vrf
->vrf_id
;
597 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
603 DEFUN_NOSH (show_debugging_sharpd
,
604 show_debugging_sharpd_cmd
,
605 "show debugging [sharp]",
608 "Sharp Information\n")
610 vty_out(vty
, "Sharp debugging status:\n");
615 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
616 "sharp lsp [update]$update (0-100000)$inlabel\
617 nexthop-group NHGNAME$nhgname\
618 [prefix A.B.C.D/M$pfx\
619 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
620 "Sharp Routing Protocol\n"
623 "The ingress label to use\n"
624 "Use nexthops from a nexthop-group\n"
625 "The nexthop-group name\n"
627 "The v4 prefix to label\n"
628 FRR_IP_REDIST_HELP_STR_ZEBRA
632 struct nexthop_group_cmd
*nhgc
= NULL
;
633 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
634 struct nexthop_group
*backup_nhg
= NULL
;
635 struct prefix p
= {};
639 update_p
= (update
!= NULL
);
641 /* We're offered a v4 prefix */
642 if (pfx
->family
> 0 && type_str
) {
643 p
.family
= pfx
->family
;
644 p
.prefixlen
= pfx
->prefixlen
;
645 p
.u
.prefix4
= pfx
->prefix
;
647 type
= proto_redistnum(AFI_IP
, type_str
);
649 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
652 } else if (pfx
->family
> 0 || type_str
) {
653 vty_out(vty
, "%% Must supply both prefix and type\n");
657 nhgc
= nhgc_find(nhgname
);
659 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
664 if (nhgc
->nhg
.nexthop
== NULL
) {
665 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
669 /* Use group's backup nexthop info if present */
670 if (nhgc
->backup_list_name
[0]) {
671 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
675 "%% Backup group %s not found for group %s\n",
676 nhgc
->backup_list_name
,
680 backup_nhg
= &(backup_nhgc
->nhg
);
683 if (sharp_install_lsps_helper(true /*install*/, update_p
,
684 pfx
->family
> 0 ? &p
: NULL
,
685 type
, instance
, inlabel
,
686 &(nhgc
->nhg
), backup_nhg
) == 0)
689 vty_out(vty
, "%% LSP install failed!\n");
694 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
697 [nexthop-group NHGNAME$nhgname] \
698 [prefix A.B.C.D/M$pfx\
699 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
700 "Sharp Routing Protocol\n"
703 "The ingress label\n"
704 "Use nexthops from a nexthop-group\n"
705 "The nexthop-group name\n"
706 "Specify a v4 prefix\n"
707 "The v4 prefix to label\n"
708 FRR_IP_REDIST_HELP_STR_ZEBRA
712 struct nexthop_group_cmd
*nhgc
= NULL
;
713 struct prefix p
= {};
715 struct nexthop_group
*nhg
= NULL
;
717 /* We're offered a v4 prefix */
718 if (pfx
->family
> 0 && type_str
) {
719 p
.family
= pfx
->family
;
720 p
.prefixlen
= pfx
->prefixlen
;
721 p
.u
.prefix4
= pfx
->prefix
;
723 type
= proto_redistnum(AFI_IP
, type_str
);
725 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
728 } else if (pfx
->family
> 0 || type_str
) {
729 vty_out(vty
, "%% Must supply both prefix and type\n");
734 nhgc
= nhgc_find(nhgname
);
736 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
741 if (nhgc
->nhg
.nexthop
== NULL
) {
742 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
749 if (sharp_install_lsps_helper(false /*!install*/, false,
750 pfx
->family
> 0 ? &p
: NULL
,
751 type
, instance
, inlabel
, nhg
, NULL
) == 0)
754 vty_out(vty
, "%% LSP remove failed!\n");
761 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
762 "Sharp Routing Protocol\n"
763 "Generate bulk log messages for testing\n"
764 "Duration of run (s)\n"
765 "Duration of run (s)\n"
766 "Frequency of bursts (s^-1)\n"
767 "Frequency of bursts (s^-1)\n"
768 "Number of log messages per each burst\n"
769 "Number of log messages per each burst\n")
771 sharp_logpump_run(vty
, duration
, frequency
, burst
);
775 DEFPY (create_session
,
777 "sharp create session (1-1024)",
778 "Sharp Routing Protocol\n"
780 "Create a test session\n"
783 if (sharp_zclient_create(session
) != 0) {
784 vty_out(vty
, "%% Client session error\n");
791 DEFPY (remove_session
,
793 "sharp remove session (1-1024)",
794 "Sharp Routing Protocol\n"
796 "Remove a test session\n"
799 sharp_zclient_delete(session
);
805 "sharp send opaque type (1-255) (1-1000)$count",
807 "Send messages for testing\n"
808 "Send opaque messages\n"
809 "Type code to send\n"
810 "Type code to send\n"
811 "Number of messages to send\n")
813 sharp_opaque_send(type
, 0, 0, 0, count
);
817 DEFPY (send_opaque_unicast
,
818 send_opaque_unicast_cmd
,
819 "sharp send opaque unicast type (1-255) \
820 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
821 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
823 "Send messages for testing\n"
824 "Send opaque messages\n"
825 "Send unicast messages\n"
826 "Type code to send\n"
827 "Type code to send\n"
828 FRR_IP_REDIST_HELP_STR_ZEBRA
833 "Number of messages to send\n")
837 proto
= proto_redistnum(AFI_IP
, proto_str
);
839 sharp_opaque_send(type
, proto
, instance
, session
, count
);
844 DEFPY (send_opaque_reg
,
846 "sharp send opaque <reg$reg | unreg> \
847 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
848 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
850 "Send messages for testing\n"
851 "Send opaque messages\n"
852 "Send opaque registration\n"
853 "Send opaque unregistration\n"
854 FRR_IP_REDIST_HELP_STR_ZEBRA
859 "Opaque sub-type code\n"
860 "Opaque sub-type code\n")
864 proto
= proto_redistnum(AFI_IP
, proto_str
);
866 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
870 DEFPY (neigh_discover
,
872 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
874 "Discover neighbours\n"
875 "Send an ARP/NDP request\n"
877 "v4 Destination address\n"
878 "v6 Destination address\n"
882 struct interface
*ifp
;
883 struct prefix prefix
;
885 memset(&prefix
, 0, sizeof(prefix
));
887 if (dst4
.s_addr
!= INADDR_ANY
) {
888 prefix
.family
= AF_INET
;
889 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
890 prefix
.u
.prefix4
= dst4
;
892 prefix
.family
= AF_INET6
;
893 prefix
.prefixlen
= 128;
894 prefix
.u
.prefix6
= dst6
;
897 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
899 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
900 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
904 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
906 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
910 sharp_zebra_send_arp(ifp
, &prefix
);
919 "Import Traffic Engineering\n")
921 sg
.ted
= ls_ted_new(1, "Sharp", 0);
922 sharp_zebra_register_te();
927 DEFPY (sharp_srv6_manager_get_locator_chunk
,
928 sharp_srv6_manager_get_locator_chunk_cmd
,
929 "sharp srv6-manager get-locator-chunk NAME$locator_name",
931 "Segment-Routing IPv6\n"
932 "Get SRv6 locator-chunk\n"
933 "SRv6 Locator name\n")
936 struct listnode
*node
;
937 struct sharp_srv6_locator
*loc
;
938 struct sharp_srv6_locator
*loc_found
= NULL
;
940 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, node
, loc
)) {
941 if (strcmp(loc
->name
, locator_name
))
947 loc
= XCALLOC(MTYPE_SRV6_LOCATOR
,
948 sizeof(struct sharp_srv6_locator
));
949 loc
->chunks
= list_new();
950 snprintf(loc
->name
, SRV6_LOCNAME_SIZE
, "%s", locator_name
);
951 listnode_add(sg
.srv6_locators
, loc
);
954 ret
= sharp_zebra_srv6_manager_get_locator_chunk(locator_name
);
956 return CMD_WARNING_CONFIG_FAILED
;
961 DEFUN (show_sharp_ted
,
963 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
966 "Traffic Engineering Database\n"
968 "MPLS-TE router ID (as an IP address)\n"
970 "MPLS-TE Edge ID (as an IP address)\n"
972 "MPLS-TE Subnet ID (as an IP prefix)\n"
977 struct in_addr ip_addr
;
979 struct ls_vertex
*vertex
;
980 struct ls_edge
*edge
;
981 struct ls_subnet
*subnet
;
983 bool verbose
= false;
984 bool uj
= use_json(argc
, argv
);
985 json_object
*json
= NULL
;
987 if (sg
.ted
== NULL
) {
988 vty_out(vty
, "MPLS-TE import is not enabled\n");
993 json
= json_object_new_object();
995 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
998 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1000 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1001 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
1003 "Specified Router ID %s is invalid\n",
1004 argv
[idx
+ 1]->arg
);
1005 return CMD_WARNING_CONFIG_FAILED
;
1007 /* Get the Vertex from the Link State Database */
1008 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1009 vertex
= ls_find_vertex_by_key(sg
.ted
, key
);
1011 vty_out(vty
, "No vertex found for ID %pI4\n",
1019 ls_show_vertex(vertex
, vty
, json
, verbose
);
1021 ls_show_vertices(sg
.ted
, vty
, json
, verbose
);
1023 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1025 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1026 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
1028 "Specified Edge ID %s is invalid\n",
1030 return CMD_WARNING_CONFIG_FAILED
;
1032 /* Get the Edge from the Link State Database */
1033 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1034 edge
= ls_find_edge_by_key(sg
.ted
, key
);
1036 vty_out(vty
, "No edge found for ID %pI4\n",
1044 ls_show_edge(edge
, vty
, json
, verbose
);
1046 ls_show_edges(sg
.ted
, vty
, json
, verbose
);
1048 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1050 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1051 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1052 vty_out(vty
, "Invalid prefix format %s\n",
1054 return CMD_WARNING_CONFIG_FAILED
;
1056 /* Get the Subnet from the Link State Database */
1057 subnet
= ls_find_subnet(sg
.ted
, pref
);
1059 vty_out(vty
, "No subnet found for ID %pFX\n",
1067 ls_show_subnet(subnet
, vty
, json
, verbose
);
1069 ls_show_subnets(sg
.ted
, vty
, json
, verbose
);
1072 /* Show the complete TED */
1073 ls_show_ted(sg
.ted
, vty
, json
, verbose
);
1077 vty_json(vty
, json
);
1082 DEFPY (sharp_srv6_manager_release_locator_chunk
,
1083 sharp_srv6_manager_release_locator_chunk_cmd
,
1084 "sharp srv6-manager release-locator-chunk NAME$locator_name",
1086 "Segment-Routing IPv6\n"
1087 "Release SRv6 locator-chunk\n"
1088 "SRv6 Locator name\n")
1091 struct listnode
*loc_node
;
1092 struct sharp_srv6_locator
*loc
;
1094 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1095 if (!strcmp(loc
->name
, locator_name
)) {
1096 list_delete_all_node(loc
->chunks
);
1097 list_delete(&loc
->chunks
);
1098 listnode_delete(sg
.srv6_locators
, loc
);
1103 ret
= sharp_zebra_srv6_manager_release_locator_chunk(locator_name
);
1105 return CMD_WARNING_CONFIG_FAILED
;
1110 DEFPY (show_sharp_segment_routing_srv6
,
1111 show_sharp_segment_routing_srv6_cmd
,
1112 "show sharp segment-routing srv6 [json]",
1116 "Segment-Routing IPv6\n"
1120 struct listnode
*loc_node
;
1121 struct listnode
*chunk_node
;
1122 struct sharp_srv6_locator
*loc
;
1123 struct prefix_ipv6
*chunk
;
1124 bool uj
= use_json(argc
, argv
);
1125 json_object
*jo_locs
= NULL
;
1126 json_object
*jo_loc
= NULL
;
1127 json_object
*jo_chunks
= NULL
;
1130 jo_locs
= json_object_new_array();
1131 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1132 jo_loc
= json_object_new_object();
1133 json_object_array_add(jo_locs
, jo_loc
);
1134 json_object_string_add(jo_loc
, "name", loc
->name
);
1135 jo_chunks
= json_object_new_array();
1136 json_object_object_add(jo_loc
, "chunks", jo_chunks
);
1137 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1139 prefix2str(chunk
, str
, sizeof(str
));
1140 json_array_string_add(jo_chunks
, str
);
1144 vty_json(vty
, jo_locs
);
1146 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1147 vty_out(vty
, "Locator %s has %d prefix chunks\n",
1148 loc
->name
, listcount(loc
->chunks
));
1149 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1151 prefix2str(chunk
, str
, sizeof(str
));
1152 vty_out(vty
, " %s\n", str
);
1161 DEFPY (show_sharp_cspf
,
1162 show_sharp_cspf_cmd
,
1163 "show sharp cspf source <A.B.C.D$src4|X:X::X:X$src6> \
1164 destination <A.B.C.D$dst4|X:X::X:X$dst6> \
1165 <metric|te-metric|delay> (0-16777215)$cost \
1166 [rsv-bw (0-7)$cos BANDWIDTH$bw]",
1169 "Constraint Shortest Path First path computation\n"
1170 "Source of the path\n"
1171 "IPv4 Source address in dot decimal A.B.C.D\n"
1172 "IPv6 Source address as X:X:X:X\n"
1173 "Destination of the path\n"
1174 "IPv4 Destination address in dot decimal A.B.C.D\n"
1175 "IPv6 Destination address as X:X:X:X\n"
1177 "Maximum TE Metric\n"
1179 "Value of Maximum cost\n"
1180 "Reserved Bandwidth of this path\n"
1181 "Class of Service or Priority level\n"
1182 "Bytes/second (IEEE floating point format)\n")
1186 struct constraints csts
;
1187 struct c_path
*path
;
1188 struct listnode
*node
;
1189 struct ls_edge
*edge
;
1192 if (sg
.ted
== NULL
) {
1193 vty_out(vty
, "MPLS-TE import is not enabled\n");
1197 if ((src4
.s_addr
!= INADDR_ANY
&& dst4
.s_addr
== INADDR_ANY
) ||
1198 (src4
.s_addr
== INADDR_ANY
&& dst4
.s_addr
!= INADDR_ANY
)) {
1199 vty_out(vty
, "Don't mix IPv4 and IPv6 addresses\n");
1204 memset(&csts
, 0, sizeof(struct constraints
));
1205 if (argv_find(argv
, argc
, "metric", &idx
)) {
1206 csts
.ctype
= CSPF_METRIC
;
1210 if (argv_find(argv
, argc
, "te-metric", &idx
)) {
1211 csts
.ctype
= CSPF_TE_METRIC
;
1215 if (argv_find(argv
, argc
, "delay", &idx
)) {
1216 csts
.ctype
= CSPF_DELAY
;
1220 if (sscanf(bw
, "%g", &csts
.bw
) != 1) {
1221 vty_out(vty
, "Bandwidth constraints: fscanf: %s\n",
1222 safe_strerror(errno
));
1223 return CMD_WARNING_CONFIG_FAILED
;
1228 /* Initialize and call point-to-point Path computation */
1229 if (src4
.s_addr
!= INADDR_ANY
)
1230 algo
= cspf_init_v4(NULL
, sg
.ted
, src4
, dst4
, &csts
);
1232 algo
= cspf_init_v6(NULL
, sg
.ted
, src6
, dst6
, &csts
);
1233 path
= compute_p2p_path(algo
, sg
.ted
);
1237 vty_out(vty
, "Path computation failed without error\n");
1240 if (path
->status
!= SUCCESS
) {
1241 vty_out(vty
, "Path computation failed: %d\n", path
->status
);
1245 vty_out(vty
, "Path computation success\n");
1246 vty_out(vty
, "\tCost: %d\n", path
->weight
);
1247 vty_out(vty
, "\tEdges:");
1248 for (ALL_LIST_ELEMENTS_RO(path
->edges
, node
, edge
)) {
1249 if (src4
.s_addr
!= INADDR_ANY
)
1250 vty_out(vty
, " %pI4",
1251 &edge
->attributes
->standard
.remote
);
1253 vty_out(vty
, " %pI6",
1254 &edge
->attributes
->standard
.remote6
);
1261 static struct interface
*if_lookup_vrf_all(const char *ifname
)
1263 struct interface
*ifp
;
1266 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1267 ifp
= if_lookup_by_name(ifname
, vrf
->vrf_id
);
1275 DEFPY (sharp_interface_protodown
,
1276 sharp_interface_protodown_cmd
,
1277 "sharp interface IFNAME$ifname protodown",
1281 "Set interface protodown\n")
1283 struct interface
*ifp
;
1285 ifp
= if_lookup_vrf_all(ifname
);
1288 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1292 if (sharp_zebra_send_interface_protodown(ifp
, true) != 0)
1298 DEFPY (no_sharp_interface_protodown
,
1299 no_sharp_interface_protodown_cmd
,
1300 "no sharp interface IFNAME$ifname protodown",
1305 "Set interface protodown\n")
1307 struct interface
*ifp
;
1309 ifp
= if_lookup_vrf_all(ifname
);
1312 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1316 if (sharp_zebra_send_interface_protodown(ifp
, false) != 0)
1322 void sharp_vty_init(void)
1324 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
1325 install_element(ENABLE_NODE
, &install_routes_cmd
);
1326 install_element(ENABLE_NODE
, &install_seg6_routes_cmd
);
1327 install_element(ENABLE_NODE
, &install_seg6local_routes_cmd
);
1328 install_element(ENABLE_NODE
, &remove_routes_cmd
);
1329 install_element(ENABLE_NODE
, &vrf_label_cmd
);
1330 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
1331 install_element(ENABLE_NODE
, &watch_redistribute_cmd
);
1332 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
1333 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
1334 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
1335 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
1336 install_element(ENABLE_NODE
, &logpump_cmd
);
1337 install_element(ENABLE_NODE
, &create_session_cmd
);
1338 install_element(ENABLE_NODE
, &remove_session_cmd
);
1339 install_element(ENABLE_NODE
, &send_opaque_cmd
);
1340 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
1341 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
1342 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
1343 install_element(ENABLE_NODE
, &import_te_cmd
);
1345 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);
1346 install_element(ENABLE_NODE
, &show_sharp_ted_cmd
);
1347 install_element(ENABLE_NODE
, &show_sharp_cspf_cmd
);
1349 install_element(ENABLE_NODE
, &sharp_srv6_manager_get_locator_chunk_cmd
);
1350 install_element(ENABLE_NODE
,
1351 &sharp_srv6_manager_release_locator_chunk_cmd
);
1352 install_element(ENABLE_NODE
, &show_sharp_segment_routing_srv6_cmd
);
1354 install_element(ENABLE_NODE
, &sharp_interface_protodown_cmd
);
1355 install_element(ENABLE_NODE
, &no_sharp_interface_protodown_cmd
);