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 #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
));
100 p
.prefixlen
= IPV6_MAX_BITLEN
;
101 memcpy(&p
.u
.prefix6
, &nhop
, IPV6_MAX_BYTELEN
);
105 prefix_copy(&p
, 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
));
144 p
.prefixlen
= IPV4_MAX_BITLEN
;
150 prefix_copy(&p
, 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 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
236 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
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 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
380 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
381 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
382 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
383 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
384 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
385 sg
.r
.opaque
[0] = '\0';
388 if (start4
.s_addr
!= INADDR_ANY
) {
389 prefix
.family
= AF_INET
;
390 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
391 prefix
.u
.prefix4
= start4
;
393 prefix
.family
= AF_INET6
;
394 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
395 prefix
.u
.prefix6
= start6
;
397 sg
.r
.orig_prefix
= prefix
;
400 vrf_name
= VRF_DEFAULT_NAME
;
402 vrf
= vrf_lookup_by_name(vrf_name
);
404 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
409 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
410 sg
.r
.nhop
.gate
.ipv6
= seg6_nh6
;
411 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
412 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
413 nexthop_add_srv6_seg6(&sg
.r
.nhop
, &seg6_seg
);
415 sg
.r
.vrf_id
= vrf
->vrf_id
;
416 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, 0,
417 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
418 routes
, route_flags
, sg
.r
.opaque
);
423 DEFPY (install_seg6local_routes
,
424 install_seg6local_routes_cmd
,
425 "sharp install seg6local-routes [vrf NAME$vrf_name]\
427 nexthop-seg6local NAME$seg6l_oif\
429 End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
430 End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
431 End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
432 End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
433 End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table|\
434 End_DT46$seg6l_enddt46 (1-4294967295)$seg6l_enddt46_table>\
435 (1-1000000)$routes [repeat (2-1000)$rpt]",
436 "Sharp routing Protocol\n"
437 "install some routes\n"
438 "Routes to install\n"
439 "The vrf we would like to install into if non-default\n"
440 "The NAME of the vrf\n"
441 "v6 Address to start /32 generation at\n"
442 "Nexthop-seg6local to use\n"
443 "Output device to use\n"
444 "SRv6 End function to use\n"
445 "SRv6 End.X function to use\n"
446 "V6 Nexthop address to use\n"
447 "SRv6 End.T function to use\n"
448 "Redirect table id to use\n"
449 "SRv6 End.DX4 function to use\n"
450 "V4 Nexthop address to use\n"
451 "SRv6 End.DT6 function to use\n"
452 "Redirect table id to use\n"
453 "SRv6 End.DT4 function to use\n"
454 "Redirect table id to use\n"
455 "SRv6 End.DT46 function to use\n"
456 "Redirect table id to use\n"
457 "How many to create\n"
458 "Should we repeat this command\n"
459 "How many times to repeat this command\n")
462 uint32_t route_flags
= 0;
463 struct seg6local_context ctx
= {};
464 enum seg6local_action_t action
;
466 sg
.r
.total_routes
= routes
;
467 sg
.r
.installed_routes
= 0;
470 sg
.r
.repeat
= rpt
* 2;
474 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
475 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
476 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
477 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
478 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
479 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
480 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
481 sg
.r
.opaque
[0] = '\0';
483 sg
.r
.orig_prefix
.family
= AF_INET6
;
484 sg
.r
.orig_prefix
.prefixlen
= 128;
485 sg
.r
.orig_prefix
.u
.prefix6
= start6
;
488 vrf_name
= VRF_DEFAULT_NAME
;
490 vrf
= vrf_lookup_by_name(vrf_name
);
492 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
498 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DX4
;
499 ctx
.nh4
= seg6l_enddx4_nh4
;
500 } else if (seg6l_endx
) {
501 action
= ZEBRA_SEG6_LOCAL_ACTION_END_X
;
502 ctx
.nh6
= seg6l_endx_nh6
;
503 } else if (seg6l_endt
) {
504 action
= ZEBRA_SEG6_LOCAL_ACTION_END_T
;
505 ctx
.table
= seg6l_endt_table
;
506 } else if (seg6l_enddt6
) {
507 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT6
;
508 ctx
.table
= seg6l_enddt6_table
;
509 } else if (seg6l_enddt4
) {
510 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT4
;
511 ctx
.table
= seg6l_enddt4_table
;
512 } else if (seg6l_enddt46
) {
513 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT46
;
514 ctx
.table
= seg6l_enddt46_table
;
516 action
= ZEBRA_SEG6_LOCAL_ACTION_END
;
519 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
520 sg
.r
.nhop
.ifindex
= ifname2ifindex(seg6l_oif
, vrf
->vrf_id
);
521 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
522 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
523 nexthop_add_srv6_seg6local(&sg
.r
.nhop
, action
, &ctx
);
525 sg
.r
.vrf_id
= vrf
->vrf_id
;
526 sharp_install_routes_helper(&sg
.r
.orig_prefix
, sg
.r
.vrf_id
, sg
.r
.inst
,
528 &sg
.r
.backup_nhop_group
, routes
,
529 route_flags
, sg
.r
.opaque
);
534 DEFPY(vrf_label
, vrf_label_cmd
,
535 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
536 "Sharp Routing Protocol\n"
537 "Give a vrf a label\n"
538 "Pop and forward for IPv4\n"
539 "Pop and forward for IPv6\n"
541 "The label to use, 0 specifies remove the label installed from previous\n"
542 "Specified range to use\n")
545 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
547 if (strcmp(vrf_name
, "default") == 0)
548 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
550 vrf
= vrf_lookup_by_name(vrf_name
);
553 vty_out(vty
, "Unable to find vrf you silly head\n");
554 return CMD_WARNING_CONFIG_FAILED
;
558 label
= MPLS_LABEL_NONE
;
560 vrf_label_add(vrf
->vrf_id
, afi
, label
);
564 DEFPY (remove_routes
,
566 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
567 "Sharp Routing Protocol\n"
568 "Remove some routes\n"
570 "The vrf we would like to remove from if non-default\n"
571 "The NAME of the vrf\n"
574 "Routes to uninstall\n"
576 "Value of instance\n")
579 struct prefix prefix
;
581 sg
.r
.total_routes
= routes
;
582 sg
.r
.removed_routes
= 0;
585 memset(&prefix
, 0, sizeof(prefix
));
587 if (start4
.s_addr
!= INADDR_ANY
) {
588 prefix
.family
= AF_INET
;
589 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
590 prefix
.u
.prefix4
= start4
;
592 prefix
.family
= AF_INET6
;
593 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
594 prefix
.u
.prefix6
= start6
;
597 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
599 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
600 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
604 sg
.r
.inst
= instance
;
605 sg
.r
.vrf_id
= vrf
->vrf_id
;
607 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
613 DEFUN_NOSH (show_debugging_sharpd
,
614 show_debugging_sharpd_cmd
,
615 "show debugging [sharp]",
618 "Sharp Information\n")
620 vty_out(vty
, "Sharp debugging status:\n");
622 cmd_show_lib_debugs(vty
);
627 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
628 "sharp lsp [update]$update (0-100000)$inlabel\
629 nexthop-group NHGNAME$nhgname\
630 [prefix A.B.C.D/M$pfx\
631 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
632 "Sharp Routing Protocol\n"
635 "The ingress label to use\n"
636 "Use nexthops from a nexthop-group\n"
637 "The nexthop-group name\n"
639 "The v4 prefix to label\n"
640 FRR_IP_REDIST_HELP_STR_ZEBRA
644 struct nexthop_group_cmd
*nhgc
= NULL
;
645 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
646 struct nexthop_group
*backup_nhg
= NULL
;
647 struct prefix p
= {};
651 update_p
= (update
!= NULL
);
653 /* We're offered a v4 prefix */
654 if (pfx
->family
> 0 && type_str
) {
655 p
.family
= pfx
->family
;
656 p
.prefixlen
= pfx
->prefixlen
;
657 p
.u
.prefix4
= pfx
->prefix
;
659 type
= proto_redistnum(AFI_IP
, type_str
);
661 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
664 } else if (pfx
->family
> 0 || type_str
) {
665 vty_out(vty
, "%% Must supply both prefix and type\n");
669 nhgc
= nhgc_find(nhgname
);
671 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
676 if (nhgc
->nhg
.nexthop
== NULL
) {
677 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
681 /* Use group's backup nexthop info if present */
682 if (nhgc
->backup_list_name
[0]) {
683 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
687 "%% Backup group %s not found for group %s\n",
688 nhgc
->backup_list_name
,
692 backup_nhg
= &(backup_nhgc
->nhg
);
695 if (sharp_install_lsps_helper(true /*install*/, update_p
,
696 pfx
->family
> 0 ? &p
: NULL
,
697 type
, instance
, inlabel
,
698 &(nhgc
->nhg
), backup_nhg
) == 0)
701 vty_out(vty
, "%% LSP install failed!\n");
706 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
709 [nexthop-group NHGNAME$nhgname] \
710 [prefix A.B.C.D/M$pfx\
711 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
712 "Sharp Routing Protocol\n"
715 "The ingress label\n"
716 "Use nexthops from a nexthop-group\n"
717 "The nexthop-group name\n"
718 "Specify a v4 prefix\n"
719 "The v4 prefix to label\n"
720 FRR_IP_REDIST_HELP_STR_ZEBRA
724 struct nexthop_group_cmd
*nhgc
= NULL
;
725 struct prefix p
= {};
727 struct nexthop_group
*nhg
= NULL
;
729 /* We're offered a v4 prefix */
730 if (pfx
->family
> 0 && type_str
) {
731 p
.family
= pfx
->family
;
732 p
.prefixlen
= pfx
->prefixlen
;
733 p
.u
.prefix4
= pfx
->prefix
;
735 type
= proto_redistnum(AFI_IP
, type_str
);
737 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
740 } else if (pfx
->family
> 0 || type_str
) {
741 vty_out(vty
, "%% Must supply both prefix and type\n");
746 nhgc
= nhgc_find(nhgname
);
748 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
753 if (nhgc
->nhg
.nexthop
== NULL
) {
754 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
761 if (sharp_install_lsps_helper(false /*!install*/, false,
762 pfx
->family
> 0 ? &p
: NULL
,
763 type
, instance
, inlabel
, nhg
, NULL
) == 0)
766 vty_out(vty
, "%% LSP remove failed!\n");
773 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
774 "Sharp Routing Protocol\n"
775 "Generate bulk log messages for testing\n"
776 "Duration of run (s)\n"
777 "Duration of run (s)\n"
778 "Frequency of bursts (s^-1)\n"
779 "Frequency of bursts (s^-1)\n"
780 "Number of log messages per each burst\n"
781 "Number of log messages per each burst\n")
783 sharp_logpump_run(vty
, duration
, frequency
, burst
);
787 DEFPY (create_session
,
789 "sharp create session (1-1024)",
790 "Sharp Routing Protocol\n"
792 "Create a test session\n"
795 if (sharp_zclient_create(session
) != 0) {
796 vty_out(vty
, "%% Client session error\n");
803 DEFPY (remove_session
,
805 "sharp remove session (1-1024)",
806 "Sharp Routing Protocol\n"
808 "Remove a test session\n"
811 sharp_zclient_delete(session
);
817 "sharp send opaque type (1-255) (1-1000)$count",
819 "Send messages for testing\n"
820 "Send opaque messages\n"
821 "Type code to send\n"
822 "Type code to send\n"
823 "Number of messages to send\n")
825 sharp_opaque_send(type
, 0, 0, 0, count
);
829 DEFPY (send_opaque_unicast
,
830 send_opaque_unicast_cmd
,
831 "sharp send opaque unicast type (1-255) \
832 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
833 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
835 "Send messages for testing\n"
836 "Send opaque messages\n"
837 "Send unicast messages\n"
838 "Type code to send\n"
839 "Type code to send\n"
840 FRR_IP_REDIST_HELP_STR_ZEBRA
845 "Number of messages to send\n")
849 proto
= proto_redistnum(AFI_IP
, proto_str
);
851 sharp_opaque_send(type
, proto
, instance
, session
, count
);
856 DEFPY (send_opaque_reg
,
858 "sharp send opaque <reg$reg | unreg> \
859 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
860 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
862 "Send messages for testing\n"
863 "Send opaque messages\n"
864 "Send opaque registration\n"
865 "Send opaque unregistration\n"
866 FRR_IP_REDIST_HELP_STR_ZEBRA
871 "Opaque sub-type code\n"
872 "Opaque sub-type code\n")
876 proto
= proto_redistnum(AFI_IP
, proto_str
);
878 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
882 DEFPY (neigh_discover
,
884 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
886 "Discover neighbours\n"
887 "Send an ARP/NDP request\n"
889 "v4 Destination address\n"
890 "v6 Destination address\n"
894 struct interface
*ifp
;
895 struct prefix prefix
;
897 memset(&prefix
, 0, sizeof(prefix
));
899 if (dst4
.s_addr
!= INADDR_ANY
) {
900 prefix
.family
= AF_INET
;
901 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
902 prefix
.u
.prefix4
= dst4
;
904 prefix
.family
= AF_INET6
;
905 prefix
.prefixlen
= 128;
906 prefix
.u
.prefix6
= dst6
;
909 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
911 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
912 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
916 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
918 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
922 sharp_zebra_send_arp(ifp
, &prefix
);
931 "Import Traffic Engineering\n")
933 sg
.ted
= ls_ted_new(1, "Sharp", 0);
934 sharp_zebra_register_te();
939 static void sharp_srv6_locator_chunk_free(struct prefix_ipv6
*chunk
)
941 prefix_ipv6_free((struct prefix_ipv6
**)&chunk
);
944 DEFPY (sharp_srv6_manager_get_locator_chunk
,
945 sharp_srv6_manager_get_locator_chunk_cmd
,
946 "sharp srv6-manager get-locator-chunk NAME$locator_name",
948 "Segment-Routing IPv6\n"
949 "Get SRv6 locator-chunk\n"
950 "SRv6 Locator name\n")
953 struct listnode
*node
;
954 struct sharp_srv6_locator
*loc
;
955 struct sharp_srv6_locator
*loc_found
= NULL
;
957 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, node
, loc
)) {
958 if (strcmp(loc
->name
, locator_name
))
964 loc
= XCALLOC(MTYPE_SRV6_LOCATOR
,
965 sizeof(struct sharp_srv6_locator
));
966 loc
->chunks
= list_new();
968 (void (*)(void *))sharp_srv6_locator_chunk_free
;
969 snprintf(loc
->name
, SRV6_LOCNAME_SIZE
, "%s", locator_name
);
970 listnode_add(sg
.srv6_locators
, loc
);
973 ret
= sharp_zebra_srv6_manager_get_locator_chunk(locator_name
);
975 return CMD_WARNING_CONFIG_FAILED
;
980 DEFUN (show_sharp_ted
,
982 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
985 "Traffic Engineering Database\n"
987 "MPLS-TE router ID (as an IP address)\n"
989 "MPLS-TE Edge ID (as an IP address)\n"
991 "MPLS-TE Subnet ID (as an IP prefix)\n"
996 struct in_addr ip_addr
;
998 struct ls_vertex
*vertex
;
999 struct ls_edge
*edge
;
1000 struct ls_subnet
*subnet
;
1002 bool verbose
= false;
1003 bool uj
= use_json(argc
, argv
);
1004 json_object
*json
= NULL
;
1006 if (sg
.ted
== NULL
) {
1007 vty_out(vty
, "MPLS-TE import is not enabled\n");
1012 json
= json_object_new_object();
1014 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
1017 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1019 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1020 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
1022 "Specified Router ID %s is invalid\n",
1023 argv
[idx
+ 1]->arg
);
1024 return CMD_WARNING_CONFIG_FAILED
;
1026 /* Get the Vertex from the Link State Database */
1027 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1028 vertex
= ls_find_vertex_by_key(sg
.ted
, key
);
1030 vty_out(vty
, "No vertex found for ID %pI4\n",
1038 ls_show_vertex(vertex
, vty
, json
, verbose
);
1040 ls_show_vertices(sg
.ted
, vty
, json
, verbose
);
1042 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1044 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1045 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
1047 "Specified Edge ID %s is invalid\n",
1049 return CMD_WARNING_CONFIG_FAILED
;
1051 /* Get the Edge from the Link State Database */
1052 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1053 edge
= ls_find_edge_by_key(sg
.ted
, key
);
1055 vty_out(vty
, "No edge found for ID %pI4\n",
1063 ls_show_edge(edge
, vty
, json
, verbose
);
1065 ls_show_edges(sg
.ted
, vty
, json
, verbose
);
1067 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1069 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1070 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1071 vty_out(vty
, "Invalid prefix format %s\n",
1073 return CMD_WARNING_CONFIG_FAILED
;
1075 /* Get the Subnet from the Link State Database */
1076 subnet
= ls_find_subnet(sg
.ted
, pref
);
1078 vty_out(vty
, "No subnet found for ID %pFX\n",
1086 ls_show_subnet(subnet
, vty
, json
, verbose
);
1088 ls_show_subnets(sg
.ted
, vty
, json
, verbose
);
1091 /* Show the complete TED */
1092 ls_show_ted(sg
.ted
, vty
, json
, verbose
);
1096 vty_json(vty
, json
);
1101 DEFPY (sharp_srv6_manager_release_locator_chunk
,
1102 sharp_srv6_manager_release_locator_chunk_cmd
,
1103 "sharp srv6-manager release-locator-chunk NAME$locator_name",
1105 "Segment-Routing IPv6\n"
1106 "Release SRv6 locator-chunk\n"
1107 "SRv6 Locator name\n")
1110 struct listnode
*loc_node
;
1111 struct sharp_srv6_locator
*loc
;
1113 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1114 if (!strcmp(loc
->name
, locator_name
)) {
1115 list_delete_all_node(loc
->chunks
);
1116 list_delete(&loc
->chunks
);
1117 listnode_delete(sg
.srv6_locators
, loc
);
1118 XFREE(MTYPE_SRV6_LOCATOR
, loc
);
1123 ret
= sharp_zebra_srv6_manager_release_locator_chunk(locator_name
);
1125 return CMD_WARNING_CONFIG_FAILED
;
1130 DEFPY (show_sharp_segment_routing_srv6
,
1131 show_sharp_segment_routing_srv6_cmd
,
1132 "show sharp segment-routing srv6 [json]",
1136 "Segment-Routing IPv6\n"
1140 struct listnode
*loc_node
;
1141 struct listnode
*chunk_node
;
1142 struct sharp_srv6_locator
*loc
;
1143 struct prefix_ipv6
*chunk
;
1144 bool uj
= use_json(argc
, argv
);
1145 json_object
*jo_locs
= NULL
;
1146 json_object
*jo_loc
= NULL
;
1147 json_object
*jo_chunks
= NULL
;
1150 jo_locs
= json_object_new_array();
1151 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1152 jo_loc
= json_object_new_object();
1153 json_object_array_add(jo_locs
, jo_loc
);
1154 json_object_string_add(jo_loc
, "name", loc
->name
);
1155 jo_chunks
= json_object_new_array();
1156 json_object_object_add(jo_loc
, "chunks", jo_chunks
);
1157 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1159 prefix2str(chunk
, str
, sizeof(str
));
1160 json_array_string_add(jo_chunks
, str
);
1164 vty_json(vty
, jo_locs
);
1166 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1167 vty_out(vty
, "Locator %s has %d prefix chunks\n",
1168 loc
->name
, listcount(loc
->chunks
));
1169 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1171 prefix2str(chunk
, str
, sizeof(str
));
1172 vty_out(vty
, " %s\n", str
);
1181 DEFPY (show_sharp_cspf
,
1182 show_sharp_cspf_cmd
,
1183 "show sharp cspf source <A.B.C.D$src4|X:X::X:X$src6> \
1184 destination <A.B.C.D$dst4|X:X::X:X$dst6> \
1185 <metric|te-metric|delay> (0-16777215)$cost \
1186 [rsv-bw (0-7)$cos BANDWIDTH$bw]",
1189 "Constraint Shortest Path First path computation\n"
1190 "Source of the path\n"
1191 "IPv4 Source address in dot decimal A.B.C.D\n"
1192 "IPv6 Source address as X:X:X:X\n"
1193 "Destination of the path\n"
1194 "IPv4 Destination address in dot decimal A.B.C.D\n"
1195 "IPv6 Destination address as X:X:X:X\n"
1197 "Maximum TE Metric\n"
1199 "Value of Maximum cost\n"
1200 "Reserved Bandwidth of this path\n"
1201 "Class of Service or Priority level\n"
1202 "Bytes/second (IEEE floating point format)\n")
1206 struct constraints csts
;
1207 struct c_path
*path
;
1208 struct listnode
*node
;
1209 struct ls_edge
*edge
;
1212 if (sg
.ted
== NULL
) {
1213 vty_out(vty
, "MPLS-TE import is not enabled\n");
1217 if ((src4
.s_addr
!= INADDR_ANY
&& dst4
.s_addr
== INADDR_ANY
) ||
1218 (src4
.s_addr
== INADDR_ANY
&& dst4
.s_addr
!= INADDR_ANY
)) {
1219 vty_out(vty
, "Don't mix IPv4 and IPv6 addresses\n");
1224 memset(&csts
, 0, sizeof(struct constraints
));
1225 if (argv_find(argv
, argc
, "metric", &idx
)) {
1226 csts
.ctype
= CSPF_METRIC
;
1230 if (argv_find(argv
, argc
, "te-metric", &idx
)) {
1231 csts
.ctype
= CSPF_TE_METRIC
;
1235 if (argv_find(argv
, argc
, "delay", &idx
)) {
1236 csts
.ctype
= CSPF_DELAY
;
1240 if (sscanf(bw
, "%g", &csts
.bw
) != 1) {
1241 vty_out(vty
, "Bandwidth constraints: fscanf: %s\n",
1242 safe_strerror(errno
));
1243 return CMD_WARNING_CONFIG_FAILED
;
1248 /* Initialize and call point-to-point Path computation */
1249 if (src4
.s_addr
!= INADDR_ANY
)
1250 algo
= cspf_init_v4(NULL
, sg
.ted
, src4
, dst4
, &csts
);
1252 algo
= cspf_init_v6(NULL
, sg
.ted
, src6
, dst6
, &csts
);
1253 path
= compute_p2p_path(algo
, sg
.ted
);
1257 vty_out(vty
, "Path computation failed without error\n");
1260 if (path
->status
!= SUCCESS
) {
1261 vty_out(vty
, "Path computation failed: %d\n", path
->status
);
1265 vty_out(vty
, "Path computation success\n");
1266 vty_out(vty
, "\tCost: %d\n", path
->weight
);
1267 vty_out(vty
, "\tEdges:");
1268 for (ALL_LIST_ELEMENTS_RO(path
->edges
, node
, edge
)) {
1269 if (src4
.s_addr
!= INADDR_ANY
)
1270 vty_out(vty
, " %pI4",
1271 &edge
->attributes
->standard
.remote
);
1273 vty_out(vty
, " %pI6",
1274 &edge
->attributes
->standard
.remote6
);
1281 static struct interface
*if_lookup_vrf_all(const char *ifname
)
1283 struct interface
*ifp
;
1286 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1287 ifp
= if_lookup_by_name(ifname
, vrf
->vrf_id
);
1295 DEFPY (sharp_interface_protodown
,
1296 sharp_interface_protodown_cmd
,
1297 "sharp interface IFNAME$ifname protodown",
1301 "Set interface protodown\n")
1303 struct interface
*ifp
;
1305 ifp
= if_lookup_vrf_all(ifname
);
1308 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1312 if (sharp_zebra_send_interface_protodown(ifp
, true) != 0)
1318 DEFPY (no_sharp_interface_protodown
,
1319 no_sharp_interface_protodown_cmd
,
1320 "no sharp interface IFNAME$ifname protodown",
1325 "Set interface protodown\n")
1327 struct interface
*ifp
;
1329 ifp
= if_lookup_vrf_all(ifname
);
1332 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1336 if (sharp_zebra_send_interface_protodown(ifp
, false) != 0)
1342 void sharp_vty_init(void)
1344 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
1345 install_element(ENABLE_NODE
, &install_routes_cmd
);
1346 install_element(ENABLE_NODE
, &install_seg6_routes_cmd
);
1347 install_element(ENABLE_NODE
, &install_seg6local_routes_cmd
);
1348 install_element(ENABLE_NODE
, &remove_routes_cmd
);
1349 install_element(ENABLE_NODE
, &vrf_label_cmd
);
1350 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
1351 install_element(ENABLE_NODE
, &watch_redistribute_cmd
);
1352 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
1353 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
1354 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
1355 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
1356 install_element(ENABLE_NODE
, &logpump_cmd
);
1357 install_element(ENABLE_NODE
, &create_session_cmd
);
1358 install_element(ENABLE_NODE
, &remove_session_cmd
);
1359 install_element(ENABLE_NODE
, &send_opaque_cmd
);
1360 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
1361 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
1362 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
1363 install_element(ENABLE_NODE
, &import_te_cmd
);
1365 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);
1366 install_element(ENABLE_NODE
, &show_sharp_ted_cmd
);
1367 install_element(ENABLE_NODE
, &show_sharp_cspf_cmd
);
1369 install_element(ENABLE_NODE
, &sharp_srv6_manager_get_locator_chunk_cmd
);
1370 install_element(ENABLE_NODE
,
1371 &sharp_srv6_manager_release_locator_chunk_cmd
);
1372 install_element(ENABLE_NODE
, &show_sharp_segment_routing_srv6_cmd
);
1374 install_element(ENABLE_NODE
, &sharp_interface_protodown_cmd
);
1375 install_element(ENABLE_NODE
, &no_sharp_interface_protodown_cmd
);