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"
37 #include "sharpd/sharp_globals.h"
38 #include "sharpd/sharp_zebra.h"
39 #include "sharpd/sharp_nht.h"
40 #include "sharpd/sharp_vty.h"
41 #include "sharpd/sharp_vty_clippy.c"
43 DEFINE_MTYPE_STATIC(SHARPD
, SRV6_LOCATOR
, "SRv6 Locator");
45 DEFPY(watch_redistribute
, watch_redistribute_cmd
,
46 "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD
,
47 "Sharp routing Protocol\n"
49 "The vrf we would like to watch if non-default\n"
50 "The NAME of the vrf\n"
51 "Redistribute into Sharp\n"
52 FRR_REDIST_HELP_STR_SHARPD
)
58 vrf_name
= VRF_DEFAULT_NAME
;
59 vrf
= vrf_lookup_by_name(vrf_name
);
61 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
66 source
= proto_redistnum(AFI_IP
, argv
[argc
-1]->text
);
67 sharp_redistribute_vrf(vrf
, source
);
72 DEFPY(watch_nexthop_v6
, watch_nexthop_v6_cmd
,
73 "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
74 "Sharp routing Protocol\n"
76 "The vrf we would like to watch if non-default\n"
77 "The NAME of the vrf\n"
78 "Watch for nexthop changes\n"
79 "The v6 nexthop to signal for watching\n"
80 "Watch for import check changes\n"
81 "The v6 prefix to signal for watching\n"
82 "Should the route be connected\n")
89 vrf_name
= VRF_DEFAULT_NAME
;
90 vrf
= vrf_lookup_by_name(vrf_name
);
92 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
97 memset(&p
, 0, sizeof(p
));
101 p
.prefixlen
= IPV6_MAX_BITLEN
;
102 memcpy(&p
.u
.prefix6
, &nhop
, IPV6_MAX_BYTELEN
);
106 prefix_copy(&p
, inhop
);
109 sharp_nh_tracker_get(&p
);
110 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
116 DEFPY(watch_nexthop_v4
, watch_nexthop_v4_cmd
,
117 "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
118 "Sharp routing Protocol\n"
119 "Watch for changes\n"
120 "The vrf we would like to watch if non-default\n"
121 "The NAME of the vrf\n"
122 "Watch for nexthop changes\n"
123 "The v4 address to signal for watching\n"
124 "Watch for import check changes\n"
125 "The v4 prefix for import check to watch\n"
126 "Should the route be connected\n")
133 vrf_name
= VRF_DEFAULT_NAME
;
134 vrf
= vrf_lookup_by_name(vrf_name
);
136 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
141 memset(&p
, 0, sizeof(p
));
145 p
.prefixlen
= IPV4_MAX_BITLEN
;
151 prefix_copy(&p
, inhop
);
154 sharp_nh_tracker_get(&p
);
155 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
161 DEFPY(sharp_nht_data_dump
,
162 sharp_nht_data_dump_cmd
,
163 "sharp data nexthop",
164 "Sharp routing Protocol\n"
165 "Data about what is going on\n"
166 "Nexthop information\n")
168 sharp_nh_tracker_dump(vty
);
173 DEFPY (install_routes_data_dump
,
174 install_routes_data_dump_cmd
,
176 "Sharp routing Protocol\n"
177 "Data about what is going on\n"
178 "Route Install/Removal Information\n")
182 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
183 vty_out(vty
, "Prefix: %pFX Total: %u %u %u Time: %jd.%ld\n",
184 &sg
.r
.orig_prefix
, sg
.r
.total_routes
, sg
.r
.installed_routes
,
185 sg
.r
.removed_routes
, (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
190 DEFPY (install_routes
,
192 "sharp install routes [vrf NAME$vrf_name]\
193 <A.B.C.D$start4|X:X::X:X$start6>\
194 <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
195 nexthop-group NHGNAME$nexthop_group>\
196 [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
197 (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]",
198 "Sharp routing Protocol\n"
199 "install some routes\n"
200 "Routes to install\n"
201 "The vrf we would like to install into if non-default\n"
202 "The NAME of the vrf\n"
203 "v4 Address to start /32 generation at\n"
204 "v6 Address to start /32 generation at\n"
205 "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
206 "V4 Nexthop address to use\n"
207 "V6 Nexthop address to use\n"
208 "Nexthop-Group to use\n"
209 "The Name of the nexthop-group\n"
210 "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
211 "Backup V4 Nexthop address to use\n"
212 "Backup V6 Nexthop address to use\n"
213 "How many to create\n"
216 "Should we repeat this command\n"
217 "How many times to repeat this command\n"
218 "What opaque data to send down\n"
222 struct prefix prefix
;
226 sg
.r
.total_routes
= routes
;
227 sg
.r
.installed_routes
= 0;
230 sg
.r
.repeat
= rpt
* 2;
234 memset(&prefix
, 0, sizeof(prefix
));
235 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
236 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
237 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
238 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
239 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
240 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
241 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
243 if (start4
.s_addr
!= INADDR_ANY
) {
244 prefix
.family
= AF_INET
;
245 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
246 prefix
.u
.prefix4
= start4
;
248 prefix
.family
= AF_INET6
;
249 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
250 prefix
.u
.prefix6
= start6
;
252 sg
.r
.orig_prefix
= prefix
;
255 vrf_name
= VRF_DEFAULT_NAME
;
257 vrf
= vrf_lookup_by_name(vrf_name
);
259 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
264 /* Explicit backup not available with named nexthop-group */
265 if (backup
&& nexthop_group
) {
266 vty_out(vty
, "%% Invalid: cannot specify both nexthop-group and backup\n");
271 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
274 "Specified Nexthop Group: %s does not exist\n",
279 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
281 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
283 /* Use group's backup nexthop info if present */
284 if (nhgc
->backup_list_name
[0]) {
285 struct nexthop_group_cmd
*bnhgc
=
286 nhgc_find(nhgc
->backup_list_name
);
289 vty_out(vty
, "%% Backup group %s not found for group %s\n",
290 nhgc
->backup_list_name
,
295 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
296 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
299 if (nexthop4
.s_addr
!= INADDR_ANY
) {
300 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
301 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
303 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
304 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
307 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
308 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
311 /* Use single backup nexthop if specified */
313 /* Set flag and index in primary nexthop */
314 SET_FLAG(sg
.r
.nhop
.flags
, NEXTHOP_FLAG_HAS_BACKUP
);
315 sg
.r
.nhop
.backup_num
= 1;
316 sg
.r
.nhop
.backup_idx
[0] = 0;
318 if (backup_nexthop4
.s_addr
!= INADDR_ANY
) {
319 sg
.r
.backup_nhop
.gate
.ipv4
= backup_nexthop4
;
320 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV4
;
322 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
323 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
326 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
327 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
331 strlcpy(sg
.r
.opaque
, opaque
, ZAPI_MESSAGE_OPAQUE_LENGTH
);
333 sg
.r
.opaque
[0] = '\0';
335 sg
.r
.inst
= instance
;
336 sg
.r
.vrf_id
= vrf
->vrf_id
;
338 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, nhgid
,
339 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
340 rts
, 0, sg
.r
.opaque
);
345 DEFPY (install_seg6_routes
,
346 install_seg6_routes_cmd
,
347 "sharp install seg6-routes [vrf NAME$vrf_name]\
348 <A.B.C.D$start4|X:X::X:X$start6>\
349 nexthop-seg6 X:X::X:X$seg6_nh6 encap X:X::X:X$seg6_seg\
350 (1-1000000)$routes [repeat (2-1000)$rpt]",
351 "Sharp routing Protocol\n"
352 "install some routes\n"
353 "Routes to install\n"
354 "The vrf we would like to install into if non-default\n"
355 "The NAME of the vrf\n"
356 "v4 Address to start /32 generation at\n"
357 "v6 Address to start /32 generation at\n"
358 "Nexthop-seg6 to use\n"
359 "V6 Nexthop address to use\n"
361 "Segment List to use\n"
362 "How many to create\n"
363 "Should we repeat this command\n"
364 "How many times to repeat this command\n")
367 struct prefix prefix
;
368 uint32_t route_flags
= 0;
370 sg
.r
.total_routes
= routes
;
371 sg
.r
.installed_routes
= 0;
374 sg
.r
.repeat
= rpt
* 2;
378 memset(&prefix
, 0, sizeof(prefix
));
379 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
380 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
381 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
382 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
383 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
384 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
385 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
386 sg
.r
.opaque
[0] = '\0';
389 if (start4
.s_addr
!= INADDR_ANY
) {
390 prefix
.family
= AF_INET
;
391 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
392 prefix
.u
.prefix4
= start4
;
394 prefix
.family
= AF_INET6
;
395 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
396 prefix
.u
.prefix6
= start6
;
398 sg
.r
.orig_prefix
= prefix
;
401 vrf_name
= VRF_DEFAULT_NAME
;
403 vrf
= vrf_lookup_by_name(vrf_name
);
405 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
410 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
411 sg
.r
.nhop
.gate
.ipv6
= seg6_nh6
;
412 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
413 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
414 nexthop_add_srv6_seg6(&sg
.r
.nhop
, &seg6_seg
);
416 sg
.r
.vrf_id
= vrf
->vrf_id
;
417 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, 0,
418 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
419 routes
, route_flags
, sg
.r
.opaque
);
424 DEFPY (install_seg6local_routes
,
425 install_seg6local_routes_cmd
,
426 "sharp install seg6local-routes [vrf NAME$vrf_name]\
428 nexthop-seg6local NAME$seg6l_oif\
430 End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
431 End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
432 End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
433 End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
434 End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table|\
435 End_DT46$seg6l_enddt46 (1-4294967295)$seg6l_enddt46_table>\
436 (1-1000000)$routes [repeat (2-1000)$rpt]",
437 "Sharp routing Protocol\n"
438 "install some routes\n"
439 "Routes to install\n"
440 "The vrf we would like to install into if non-default\n"
441 "The NAME of the vrf\n"
442 "v6 Address to start /32 generation at\n"
443 "Nexthop-seg6local to use\n"
444 "Output device to use\n"
445 "SRv6 End function to use\n"
446 "SRv6 End.X function to use\n"
447 "V6 Nexthop address to use\n"
448 "SRv6 End.T function to use\n"
449 "Redirect table id to use\n"
450 "SRv6 End.DX4 function to use\n"
451 "V4 Nexthop address to use\n"
452 "SRv6 End.DT6 function to use\n"
453 "Redirect table id to use\n"
454 "SRv6 End.DT4 function to use\n"
455 "Redirect table id to use\n"
456 "SRv6 End.DT46 function to use\n"
457 "Redirect table id to use\n"
458 "How many to create\n"
459 "Should we repeat this command\n"
460 "How many times to repeat this command\n")
463 uint32_t route_flags
= 0;
464 struct seg6local_context ctx
= {};
465 enum seg6local_action_t action
;
467 sg
.r
.total_routes
= routes
;
468 sg
.r
.installed_routes
= 0;
471 sg
.r
.repeat
= rpt
* 2;
475 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
476 nexthop_del_srv6_seg6local(&sg
.r
.nhop
);
477 nexthop_del_srv6_seg6(&sg
.r
.nhop
);
478 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
479 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
480 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
481 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
482 sg
.r
.opaque
[0] = '\0';
484 sg
.r
.orig_prefix
.family
= AF_INET6
;
485 sg
.r
.orig_prefix
.prefixlen
= 128;
486 sg
.r
.orig_prefix
.u
.prefix6
= start6
;
489 vrf_name
= VRF_DEFAULT_NAME
;
491 vrf
= vrf_lookup_by_name(vrf_name
);
493 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
499 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DX4
;
500 ctx
.nh4
= seg6l_enddx4_nh4
;
501 } else if (seg6l_endx
) {
502 action
= ZEBRA_SEG6_LOCAL_ACTION_END_X
;
503 ctx
.nh6
= seg6l_endx_nh6
;
504 } else if (seg6l_endt
) {
505 action
= ZEBRA_SEG6_LOCAL_ACTION_END_T
;
506 ctx
.table
= seg6l_endt_table
;
507 } else if (seg6l_enddt6
) {
508 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT6
;
509 ctx
.table
= seg6l_enddt6_table
;
510 } else if (seg6l_enddt4
) {
511 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT4
;
512 ctx
.table
= seg6l_enddt4_table
;
513 } else if (seg6l_enddt46
) {
514 action
= ZEBRA_SEG6_LOCAL_ACTION_END_DT46
;
515 ctx
.table
= seg6l_enddt46_table
;
517 action
= ZEBRA_SEG6_LOCAL_ACTION_END
;
520 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
521 sg
.r
.nhop
.ifindex
= ifname2ifindex(seg6l_oif
, vrf
->vrf_id
);
522 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
523 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
524 nexthop_add_srv6_seg6local(&sg
.r
.nhop
, action
, &ctx
);
526 sg
.r
.vrf_id
= vrf
->vrf_id
;
527 sharp_install_routes_helper(&sg
.r
.orig_prefix
, sg
.r
.vrf_id
, sg
.r
.inst
,
529 &sg
.r
.backup_nhop_group
, routes
,
530 route_flags
, sg
.r
.opaque
);
535 DEFPY(vrf_label
, vrf_label_cmd
,
536 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
537 "Sharp Routing Protocol\n"
538 "Give a vrf a label\n"
539 "Pop and forward for IPv4\n"
540 "Pop and forward for IPv6\n"
542 "The label to use, 0 specifies remove the label installed from previous\n"
543 "Specified range to use\n")
546 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
548 if (strcmp(vrf_name
, "default") == 0)
549 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
551 vrf
= vrf_lookup_by_name(vrf_name
);
554 vty_out(vty
, "Unable to find vrf you silly head\n");
555 return CMD_WARNING_CONFIG_FAILED
;
559 label
= MPLS_LABEL_NONE
;
561 vrf_label_add(vrf
->vrf_id
, afi
, label
);
565 DEFPY (remove_routes
,
567 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
568 "Sharp Routing Protocol\n"
569 "Remove some routes\n"
571 "The vrf we would like to remove from if non-default\n"
572 "The NAME of the vrf\n"
575 "Routes to uninstall\n"
577 "Value of instance\n")
580 struct prefix prefix
;
582 sg
.r
.total_routes
= routes
;
583 sg
.r
.removed_routes
= 0;
586 memset(&prefix
, 0, sizeof(prefix
));
588 if (start4
.s_addr
!= INADDR_ANY
) {
589 prefix
.family
= AF_INET
;
590 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
591 prefix
.u
.prefix4
= start4
;
593 prefix
.family
= AF_INET6
;
594 prefix
.prefixlen
= IPV6_MAX_BITLEN
;
595 prefix
.u
.prefix6
= start6
;
598 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
600 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
601 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
605 sg
.r
.inst
= instance
;
606 sg
.r
.vrf_id
= vrf
->vrf_id
;
608 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
614 DEFUN_NOSH (show_debugging_sharpd
,
615 show_debugging_sharpd_cmd
,
616 "show debugging [sharp]",
619 "Sharp Information\n")
621 vty_out(vty
, "Sharp debugging status:\n");
623 cmd_show_lib_debugs(vty
);
628 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
629 "sharp lsp [update]$update (0-100000)$inlabel\
630 nexthop-group NHGNAME$nhgname\
631 [prefix A.B.C.D/M$pfx\
632 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
633 "Sharp Routing Protocol\n"
636 "The ingress label to use\n"
637 "Use nexthops from a nexthop-group\n"
638 "The nexthop-group name\n"
640 "The v4 prefix to label\n"
641 FRR_IP_REDIST_HELP_STR_ZEBRA
645 struct nexthop_group_cmd
*nhgc
= NULL
;
646 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
647 struct nexthop_group
*backup_nhg
= NULL
;
648 struct prefix p
= {};
652 update_p
= (update
!= NULL
);
654 /* We're offered a v4 prefix */
655 if (pfx
->family
> 0 && type_str
) {
656 p
.family
= pfx
->family
;
657 p
.prefixlen
= pfx
->prefixlen
;
658 p
.u
.prefix4
= pfx
->prefix
;
660 type
= proto_redistnum(AFI_IP
, type_str
);
662 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
665 } else if (pfx
->family
> 0 || type_str
) {
666 vty_out(vty
, "%% Must supply both prefix and type\n");
670 nhgc
= nhgc_find(nhgname
);
672 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
677 if (nhgc
->nhg
.nexthop
== NULL
) {
678 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
682 /* Use group's backup nexthop info if present */
683 if (nhgc
->backup_list_name
[0]) {
684 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
688 "%% Backup group %s not found for group %s\n",
689 nhgc
->backup_list_name
,
693 backup_nhg
= &(backup_nhgc
->nhg
);
696 if (sharp_install_lsps_helper(true /*install*/, update_p
,
697 pfx
->family
> 0 ? &p
: NULL
,
698 type
, instance
, inlabel
,
699 &(nhgc
->nhg
), backup_nhg
) == 0)
702 vty_out(vty
, "%% LSP install failed!\n");
707 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
710 [nexthop-group NHGNAME$nhgname] \
711 [prefix A.B.C.D/M$pfx\
712 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
713 "Sharp Routing Protocol\n"
716 "The ingress label\n"
717 "Use nexthops from a nexthop-group\n"
718 "The nexthop-group name\n"
719 "Specify a v4 prefix\n"
720 "The v4 prefix to label\n"
721 FRR_IP_REDIST_HELP_STR_ZEBRA
725 struct nexthop_group_cmd
*nhgc
= NULL
;
726 struct prefix p
= {};
728 struct nexthop_group
*nhg
= NULL
;
730 /* We're offered a v4 prefix */
731 if (pfx
->family
> 0 && type_str
) {
732 p
.family
= pfx
->family
;
733 p
.prefixlen
= pfx
->prefixlen
;
734 p
.u
.prefix4
= pfx
->prefix
;
736 type
= proto_redistnum(AFI_IP
, type_str
);
738 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
741 } else if (pfx
->family
> 0 || type_str
) {
742 vty_out(vty
, "%% Must supply both prefix and type\n");
747 nhgc
= nhgc_find(nhgname
);
749 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
754 if (nhgc
->nhg
.nexthop
== NULL
) {
755 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
762 if (sharp_install_lsps_helper(false /*!install*/, false,
763 pfx
->family
> 0 ? &p
: NULL
,
764 type
, instance
, inlabel
, nhg
, NULL
) == 0)
767 vty_out(vty
, "%% LSP remove failed!\n");
774 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
775 "Sharp Routing Protocol\n"
776 "Generate bulk log messages for testing\n"
777 "Duration of run (s)\n"
778 "Duration of run (s)\n"
779 "Frequency of bursts (s^-1)\n"
780 "Frequency of bursts (s^-1)\n"
781 "Number of log messages per each burst\n"
782 "Number of log messages per each burst\n")
784 sharp_logpump_run(vty
, duration
, frequency
, burst
);
788 DEFPY (create_session
,
790 "sharp create session (1-1024)",
791 "Sharp Routing Protocol\n"
793 "Create a test session\n"
796 if (sharp_zclient_create(session
) != 0) {
797 vty_out(vty
, "%% Client session error\n");
804 DEFPY (remove_session
,
806 "sharp remove session (1-1024)",
807 "Sharp Routing Protocol\n"
809 "Remove a test session\n"
812 sharp_zclient_delete(session
);
818 "sharp send opaque type (1-255) (1-1000)$count",
820 "Send messages for testing\n"
821 "Send opaque messages\n"
822 "Type code to send\n"
823 "Type code to send\n"
824 "Number of messages to send\n")
826 sharp_opaque_send(type
, 0, 0, 0, count
);
830 DEFPY (send_opaque_unicast
,
831 send_opaque_unicast_cmd
,
832 "sharp send opaque unicast type (1-255) \
833 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
834 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
836 "Send messages for testing\n"
837 "Send opaque messages\n"
838 "Send unicast messages\n"
839 "Type code to send\n"
840 "Type code to send\n"
841 FRR_IP_REDIST_HELP_STR_ZEBRA
846 "Number of messages to send\n")
850 proto
= proto_redistnum(AFI_IP
, proto_str
);
852 sharp_opaque_send(type
, proto
, instance
, session
, count
);
857 DEFPY (send_opaque_reg
,
859 "sharp send opaque <reg$reg | unreg> \
860 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
861 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
863 "Send messages for testing\n"
864 "Send opaque messages\n"
865 "Send opaque registration\n"
866 "Send opaque unregistration\n"
867 FRR_IP_REDIST_HELP_STR_ZEBRA
872 "Opaque sub-type code\n"
873 "Opaque sub-type code\n")
877 proto
= proto_redistnum(AFI_IP
, proto_str
);
879 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
883 DEFPY (neigh_discover
,
885 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
887 "Discover neighbours\n"
888 "Send an ARP/NDP request\n"
890 "v4 Destination address\n"
891 "v6 Destination address\n"
895 struct interface
*ifp
;
896 struct prefix prefix
;
898 memset(&prefix
, 0, sizeof(prefix
));
900 if (dst4
.s_addr
!= INADDR_ANY
) {
901 prefix
.family
= AF_INET
;
902 prefix
.prefixlen
= IPV4_MAX_BITLEN
;
903 prefix
.u
.prefix4
= dst4
;
905 prefix
.family
= AF_INET6
;
906 prefix
.prefixlen
= 128;
907 prefix
.u
.prefix6
= dst6
;
910 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
912 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
913 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
917 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
919 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
923 sharp_zebra_send_arp(ifp
, &prefix
);
932 "Import Traffic Engineering\n")
934 sg
.ted
= ls_ted_new(1, "Sharp", 0);
935 sharp_zebra_register_te();
940 static void sharp_srv6_locator_chunk_free(struct prefix_ipv6
*chunk
)
942 prefix_ipv6_free((struct prefix_ipv6
**)&chunk
);
945 DEFPY (sharp_srv6_manager_get_locator_chunk
,
946 sharp_srv6_manager_get_locator_chunk_cmd
,
947 "sharp srv6-manager get-locator-chunk NAME$locator_name",
949 "Segment-Routing IPv6\n"
950 "Get SRv6 locator-chunk\n"
951 "SRv6 Locator name\n")
954 struct listnode
*node
;
955 struct sharp_srv6_locator
*loc
;
956 struct sharp_srv6_locator
*loc_found
= NULL
;
958 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, node
, loc
)) {
959 if (strcmp(loc
->name
, locator_name
))
965 loc
= XCALLOC(MTYPE_SRV6_LOCATOR
,
966 sizeof(struct sharp_srv6_locator
));
967 loc
->chunks
= list_new();
969 (void (*)(void *))sharp_srv6_locator_chunk_free
;
970 snprintf(loc
->name
, SRV6_LOCNAME_SIZE
, "%s", locator_name
);
971 listnode_add(sg
.srv6_locators
, loc
);
974 ret
= sharp_zebra_srv6_manager_get_locator_chunk(locator_name
);
976 return CMD_WARNING_CONFIG_FAILED
;
981 DEFUN (show_sharp_ted
,
983 "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]",
986 "Traffic Engineering Database\n"
988 "MPLS-TE router ID (as an IP address)\n"
990 "MPLS-TE Edge ID (as an IP address)\n"
992 "MPLS-TE Subnet ID (as an IP prefix)\n"
997 struct in_addr ip_addr
;
999 struct ls_vertex
*vertex
;
1000 struct ls_edge
*edge
;
1001 struct ls_subnet
*subnet
;
1003 bool verbose
= false;
1004 bool uj
= use_json(argc
, argv
);
1005 json_object
*json
= NULL
;
1007 if (sg
.ted
== NULL
) {
1008 vty_out(vty
, "MPLS-TE import is not enabled\n");
1013 json
= json_object_new_object();
1015 if (argv
[argc
- 1]->arg
&& strmatch(argv
[argc
- 1]->text
, "verbose"))
1018 if (argv_find(argv
, argc
, "vertex", &idx
)) {
1020 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1021 if (!inet_aton(argv
[idx
+ 1]->arg
, &ip_addr
)) {
1023 "Specified Router ID %s is invalid\n",
1024 argv
[idx
+ 1]->arg
);
1025 return CMD_WARNING_CONFIG_FAILED
;
1027 /* Get the Vertex from the Link State Database */
1028 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1029 vertex
= ls_find_vertex_by_key(sg
.ted
, key
);
1031 vty_out(vty
, "No vertex found for ID %pI4\n",
1039 ls_show_vertex(vertex
, vty
, json
, verbose
);
1041 ls_show_vertices(sg
.ted
, vty
, json
, verbose
);
1043 } else if (argv_find(argv
, argc
, "edge", &idx
)) {
1045 if (argv_find(argv
, argc
, "A.B.C.D", &idx
)) {
1046 if (!inet_aton(argv
[idx
]->arg
, &ip_addr
)) {
1048 "Specified Edge ID %s is invalid\n",
1050 return CMD_WARNING_CONFIG_FAILED
;
1052 /* Get the Edge from the Link State Database */
1053 key
= ((uint64_t)ip_addr
.s_addr
) & 0xffffffff;
1054 edge
= ls_find_edge_by_key(sg
.ted
, key
);
1056 vty_out(vty
, "No edge found for ID %pI4\n",
1064 ls_show_edge(edge
, vty
, json
, verbose
);
1066 ls_show_edges(sg
.ted
, vty
, json
, verbose
);
1068 } else if (argv_find(argv
, argc
, "subnet", &idx
)) {
1070 if (argv_find(argv
, argc
, "A.B.C.D/M", &idx
)) {
1071 if (!str2prefix(argv
[idx
]->arg
, &pref
)) {
1072 vty_out(vty
, "Invalid prefix format %s\n",
1074 return CMD_WARNING_CONFIG_FAILED
;
1076 /* Get the Subnet from the Link State Database */
1077 subnet
= ls_find_subnet(sg
.ted
, pref
);
1079 vty_out(vty
, "No subnet found for ID %pFX\n",
1087 ls_show_subnet(subnet
, vty
, json
, verbose
);
1089 ls_show_subnets(sg
.ted
, vty
, json
, verbose
);
1092 /* Show the complete TED */
1093 ls_show_ted(sg
.ted
, vty
, json
, verbose
);
1097 vty_json(vty
, json
);
1102 DEFPY (sharp_srv6_manager_release_locator_chunk
,
1103 sharp_srv6_manager_release_locator_chunk_cmd
,
1104 "sharp srv6-manager release-locator-chunk NAME$locator_name",
1106 "Segment-Routing IPv6\n"
1107 "Release SRv6 locator-chunk\n"
1108 "SRv6 Locator name\n")
1111 struct listnode
*loc_node
;
1112 struct sharp_srv6_locator
*loc
;
1114 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1115 if (!strcmp(loc
->name
, locator_name
)) {
1116 list_delete_all_node(loc
->chunks
);
1117 list_delete(&loc
->chunks
);
1118 listnode_delete(sg
.srv6_locators
, loc
);
1119 XFREE(MTYPE_SRV6_LOCATOR
, loc
);
1124 ret
= sharp_zebra_srv6_manager_release_locator_chunk(locator_name
);
1126 return CMD_WARNING_CONFIG_FAILED
;
1131 DEFPY (show_sharp_segment_routing_srv6
,
1132 show_sharp_segment_routing_srv6_cmd
,
1133 "show sharp segment-routing srv6 [json]",
1137 "Segment-Routing IPv6\n"
1141 struct listnode
*loc_node
;
1142 struct listnode
*chunk_node
;
1143 struct sharp_srv6_locator
*loc
;
1144 struct prefix_ipv6
*chunk
;
1145 bool uj
= use_json(argc
, argv
);
1146 json_object
*jo_locs
= NULL
;
1147 json_object
*jo_loc
= NULL
;
1148 json_object
*jo_chunks
= NULL
;
1151 jo_locs
= json_object_new_array();
1152 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1153 jo_loc
= json_object_new_object();
1154 json_object_array_add(jo_locs
, jo_loc
);
1155 json_object_string_add(jo_loc
, "name", loc
->name
);
1156 jo_chunks
= json_object_new_array();
1157 json_object_object_add(jo_loc
, "chunks", jo_chunks
);
1158 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1160 prefix2str(chunk
, str
, sizeof(str
));
1161 json_array_string_add(jo_chunks
, str
);
1165 vty_json(vty
, jo_locs
);
1167 for (ALL_LIST_ELEMENTS_RO(sg
.srv6_locators
, loc_node
, loc
)) {
1168 vty_out(vty
, "Locator %s has %d prefix chunks\n",
1169 loc
->name
, listcount(loc
->chunks
));
1170 for (ALL_LIST_ELEMENTS_RO(loc
->chunks
, chunk_node
,
1172 prefix2str(chunk
, str
, sizeof(str
));
1173 vty_out(vty
, " %s\n", str
);
1182 DEFPY (show_sharp_cspf
,
1183 show_sharp_cspf_cmd
,
1184 "show sharp cspf source <A.B.C.D$src4|X:X::X:X$src6> \
1185 destination <A.B.C.D$dst4|X:X::X:X$dst6> \
1186 <metric|te-metric|delay> (0-16777215)$cost \
1187 [rsv-bw (0-7)$cos BANDWIDTH$bw]",
1190 "Constraint Shortest Path First path computation\n"
1191 "Source of the path\n"
1192 "IPv4 Source address in dot decimal A.B.C.D\n"
1193 "IPv6 Source address as X:X:X:X\n"
1194 "Destination of the path\n"
1195 "IPv4 Destination address in dot decimal A.B.C.D\n"
1196 "IPv6 Destination address as X:X:X:X\n"
1198 "Maximum TE Metric\n"
1200 "Value of Maximum cost\n"
1201 "Reserved Bandwidth of this path\n"
1202 "Class of Service or Priority level\n"
1203 "Bytes/second (IEEE floating point format)\n")
1207 struct constraints csts
;
1208 struct c_path
*path
;
1209 struct listnode
*node
;
1210 struct ls_edge
*edge
;
1213 if (sg
.ted
== NULL
) {
1214 vty_out(vty
, "MPLS-TE import is not enabled\n");
1218 if ((src4
.s_addr
!= INADDR_ANY
&& dst4
.s_addr
== INADDR_ANY
) ||
1219 (src4
.s_addr
== INADDR_ANY
&& dst4
.s_addr
!= INADDR_ANY
)) {
1220 vty_out(vty
, "Don't mix IPv4 and IPv6 addresses\n");
1225 memset(&csts
, 0, sizeof(struct constraints
));
1226 if (argv_find(argv
, argc
, "metric", &idx
)) {
1227 csts
.ctype
= CSPF_METRIC
;
1231 if (argv_find(argv
, argc
, "te-metric", &idx
)) {
1232 csts
.ctype
= CSPF_TE_METRIC
;
1236 if (argv_find(argv
, argc
, "delay", &idx
)) {
1237 csts
.ctype
= CSPF_DELAY
;
1241 if (sscanf(bw
, "%g", &csts
.bw
) != 1) {
1242 vty_out(vty
, "Bandwidth constraints: fscanf: %s\n",
1243 safe_strerror(errno
));
1244 return CMD_WARNING_CONFIG_FAILED
;
1249 /* Initialize and call point-to-point Path computation */
1250 if (src4
.s_addr
!= INADDR_ANY
)
1251 algo
= cspf_init_v4(NULL
, sg
.ted
, src4
, dst4
, &csts
);
1253 algo
= cspf_init_v6(NULL
, sg
.ted
, src6
, dst6
, &csts
);
1254 path
= compute_p2p_path(algo
, sg
.ted
);
1258 vty_out(vty
, "Path computation failed without error\n");
1261 if (path
->status
!= SUCCESS
) {
1262 vty_out(vty
, "Path computation failed: %d\n", path
->status
);
1266 vty_out(vty
, "Path computation success\n");
1267 vty_out(vty
, "\tCost: %d\n", path
->weight
);
1268 vty_out(vty
, "\tEdges:");
1269 for (ALL_LIST_ELEMENTS_RO(path
->edges
, node
, edge
)) {
1270 if (src4
.s_addr
!= INADDR_ANY
)
1271 vty_out(vty
, " %pI4",
1272 &edge
->attributes
->standard
.remote
);
1274 vty_out(vty
, " %pI6",
1275 &edge
->attributes
->standard
.remote6
);
1282 static struct interface
*if_lookup_vrf_all(const char *ifname
)
1284 struct interface
*ifp
;
1287 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1288 ifp
= if_lookup_by_name(ifname
, vrf
->vrf_id
);
1296 DEFPY (sharp_interface_protodown
,
1297 sharp_interface_protodown_cmd
,
1298 "sharp interface IFNAME$ifname protodown",
1302 "Set interface protodown\n")
1304 struct interface
*ifp
;
1306 ifp
= if_lookup_vrf_all(ifname
);
1309 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1313 if (sharp_zebra_send_interface_protodown(ifp
, true) != 0)
1319 DEFPY (no_sharp_interface_protodown
,
1320 no_sharp_interface_protodown_cmd
,
1321 "no sharp interface IFNAME$ifname protodown",
1326 "Set interface protodown\n")
1328 struct interface
*ifp
;
1330 ifp
= if_lookup_vrf_all(ifname
);
1333 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1337 if (sharp_zebra_send_interface_protodown(ifp
, false) != 0)
1343 DEFPY (tc_filter_rate
,
1345 "sharp tc dev IFNAME$ifname \
1346 source <A.B.C.D/M|X:X::X:X/M>$src \
1347 destination <A.B.C.D/M|X:X::X:X/M>$dst \
1348 ip-protocol <tcp|udp>$ip_proto \
1349 src-port (1-65535)$src_port \
1350 dst-port (1-65535)$dst_port \
1354 "TC interface (for qdisc, class, filter)\n"
1355 "TC interface name\n"
1356 "TC filter source\n"
1357 "TC filter source IPv4 prefix\n"
1358 "TC filter source IPv6 prefix\n"
1359 "TC filter destination\n"
1360 "TC filter destination IPv4 prefix\n"
1361 "TC filter destination IPv6 prefix\n"
1362 "TC filter IP protocol\n"
1363 "TC filter IP protocol TCP\n"
1364 "TC filter IP protocol UDP\n"
1365 "TC filter source port\n"
1366 "TC filter source port\n"
1367 "TC filter destination port\n"
1368 "TC filter destination port\n"
1370 "TC rate number (bits/s) or rate string (suffixed with Bps or bit)\n")
1372 struct interface
*ifp
;
1376 ifp
= if_lookup_vrf_all(ifname
);
1379 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
1383 p
= getprotobyname(ip_proto
);
1385 vty_out(vty
, "Unable to convert %s to proto id\n", ip_proto
);
1389 if (tc_getrate(ratestr
, &rate
) != 0) {
1390 vty_out(vty
, "Unable to convert %s to rate\n", ratestr
);
1394 if (sharp_zebra_send_tc_filter_rate(ifp
, src
, dst
, p
->p_proto
, src_port
,
1395 dst_port
, rate
) != 0)
1401 void sharp_vty_init(void)
1403 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
1404 install_element(ENABLE_NODE
, &install_routes_cmd
);
1405 install_element(ENABLE_NODE
, &install_seg6_routes_cmd
);
1406 install_element(ENABLE_NODE
, &install_seg6local_routes_cmd
);
1407 install_element(ENABLE_NODE
, &remove_routes_cmd
);
1408 install_element(ENABLE_NODE
, &vrf_label_cmd
);
1409 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
1410 install_element(ENABLE_NODE
, &watch_redistribute_cmd
);
1411 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
1412 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
1413 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
1414 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
1415 install_element(ENABLE_NODE
, &logpump_cmd
);
1416 install_element(ENABLE_NODE
, &create_session_cmd
);
1417 install_element(ENABLE_NODE
, &remove_session_cmd
);
1418 install_element(ENABLE_NODE
, &send_opaque_cmd
);
1419 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
1420 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
1421 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
1422 install_element(ENABLE_NODE
, &import_te_cmd
);
1424 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);
1425 install_element(ENABLE_NODE
, &show_sharp_ted_cmd
);
1426 install_element(ENABLE_NODE
, &show_sharp_cspf_cmd
);
1428 install_element(ENABLE_NODE
, &sharp_srv6_manager_get_locator_chunk_cmd
);
1429 install_element(ENABLE_NODE
,
1430 &sharp_srv6_manager_release_locator_chunk_cmd
);
1431 install_element(ENABLE_NODE
, &show_sharp_segment_routing_srv6_cmd
);
1433 install_element(ENABLE_NODE
, &sharp_interface_protodown_cmd
);
1434 install_element(ENABLE_NODE
, &no_sharp_interface_protodown_cmd
);
1436 install_element(ENABLE_NODE
, &tc_filter_rate_cmd
);