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 "sharpd/sharp_globals.h"
34 #include "sharpd/sharp_zebra.h"
35 #include "sharpd/sharp_nht.h"
36 #include "sharpd/sharp_vty.h"
37 #ifndef VTYSH_EXTRACT_PL
38 #include "sharpd/sharp_vty_clippy.c"
41 DEFPY(watch_nexthop_v6
, watch_nexthop_v6_cmd
,
42 "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
43 "Sharp routing Protocol\n"
45 "The vrf we would like to watch if non-default\n"
46 "The NAME of the vrf\n"
47 "Watch for nexthop changes\n"
48 "The v6 nexthop to signal for watching\n"
49 "Watch for import check changes\n"
50 "The v6 prefix to signal for watching\n"
51 "Should the route be connected\n")
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 memset(&p
, 0, sizeof(p
));
71 memcpy(&p
.u
.prefix6
, &nhop
, 16);
75 p
= *(const struct prefix
*)inhop
;
78 sharp_nh_tracker_get(&p
);
79 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
85 DEFPY(watch_nexthop_v4
, watch_nexthop_v4_cmd
,
86 "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
87 "Sharp routing Protocol\n"
89 "The vrf we would like to watch if non-default\n"
90 "The NAME of the vrf\n"
91 "Watch for nexthop changes\n"
92 "The v4 address to signal for watching\n"
93 "Watch for import check changes\n"
94 "The v4 prefix for import check to watch\n"
95 "Should the route be connected\n")
102 vrf_name
= VRF_DEFAULT_NAME
;
103 vrf
= vrf_lookup_by_name(vrf_name
);
105 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
110 memset(&p
, 0, sizeof(p
));
120 p
= *(const struct prefix
*)inhop
;
123 sharp_nh_tracker_get(&p
);
124 sharp_zebra_nexthop_watch(&p
, vrf
->vrf_id
, type_import
,
130 DEFPY(sharp_nht_data_dump
,
131 sharp_nht_data_dump_cmd
,
132 "sharp data nexthop",
133 "Sharp routing Protocol\n"
134 "Data about what is going on\n"
135 "Nexthop information\n")
137 sharp_nh_tracker_dump(vty
);
142 DEFPY (install_routes_data_dump
,
143 install_routes_data_dump_cmd
,
145 "Sharp routing Protocol\n"
146 "Data about what is going on\n"
147 "Route Install/Removal Information\n")
149 char buf
[PREFIX_STRLEN
];
152 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
153 vty_out(vty
, "Prefix: %s Total: %u %u %u Time: %jd.%ld\n",
154 prefix2str(&sg
.r
.orig_prefix
, buf
, sizeof(buf
)),
156 sg
.r
.installed_routes
,
158 (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
163 DEFPY (install_routes
,
165 "sharp install routes [vrf NAME$vrf_name]\
166 <A.B.C.D$start4|X:X::X:X$start6>\
167 <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
168 nexthop-group NHGNAME$nexthop_group>\
169 [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
170 (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
171 "Sharp routing Protocol\n"
172 "install some routes\n"
173 "Routes to install\n"
174 "The vrf we would like to install into if non-default\n"
175 "The NAME of the vrf\n"
176 "v4 Address to start /32 generation at\n"
177 "v6 Address to start /32 generation at\n"
178 "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
179 "V4 Nexthop address to use\n"
180 "V6 Nexthop address to use\n"
181 "Nexthop-Group to use\n"
182 "The Name of the nexthop-group\n"
183 "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
184 "Backup V4 Nexthop address to use\n"
185 "Backup V6 Nexthop address to use\n"
186 "How many to create\n"
189 "Should we repeat this command\n"
190 "How many times to repeat this command\n")
193 struct prefix prefix
;
197 sg
.r
.total_routes
= routes
;
198 sg
.r
.installed_routes
= 0;
201 sg
.r
.repeat
= rpt
* 2;
205 memset(&prefix
, 0, sizeof(prefix
));
206 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
207 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
208 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
209 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
210 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
212 if (start4
.s_addr
!= 0) {
213 prefix
.family
= AF_INET
;
214 prefix
.prefixlen
= 32;
215 prefix
.u
.prefix4
= start4
;
217 prefix
.family
= AF_INET6
;
218 prefix
.prefixlen
= 128;
219 prefix
.u
.prefix6
= start6
;
221 sg
.r
.orig_prefix
= prefix
;
224 vrf_name
= VRF_DEFAULT_NAME
;
226 vrf
= vrf_lookup_by_name(vrf_name
);
228 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
233 /* Explicit backup not available with named nexthop-group */
234 if (backup
&& nexthop_group
) {
235 vty_out(vty
, "%% Invalid: cannot specify both nexthop-group and backup\n");
240 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
243 "Specified Nexthop Group: %s does not exist\n",
248 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
250 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
252 /* Use group's backup nexthop info if present */
253 if (nhgc
->backup_list_name
[0]) {
254 struct nexthop_group_cmd
*bnhgc
=
255 nhgc_find(nhgc
->backup_list_name
);
258 vty_out(vty
, "%% Backup group %s not found for group %s\n",
259 nhgc
->backup_list_name
,
264 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
265 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
268 if (nexthop4
.s_addr
!= INADDR_ANY
) {
269 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
270 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
272 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
273 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
276 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
277 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
280 /* Use single backup nexthop if specified */
282 /* Set flag and index in primary nexthop */
283 SET_FLAG(sg
.r
.nhop
.flags
, NEXTHOP_FLAG_HAS_BACKUP
);
284 sg
.r
.nhop
.backup_num
= 1;
285 sg
.r
.nhop
.backup_idx
[0] = 0;
287 if (backup_nexthop4
.s_addr
!= INADDR_ANY
) {
288 sg
.r
.backup_nhop
.gate
.ipv4
= backup_nexthop4
;
289 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV4
;
291 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
292 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
295 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
296 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
299 sg
.r
.inst
= instance
;
300 sg
.r
.vrf_id
= vrf
->vrf_id
;
302 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, nhgid
,
303 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
309 DEFPY(vrf_label
, vrf_label_cmd
,
310 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
311 "Sharp Routing Protocol\n"
312 "Give a vrf a label\n"
313 "Pop and forward for IPv4\n"
314 "Pop and forward for IPv6\n"
316 "The label to use, 0 specifies remove the label installed from previous\n"
317 "Specified range to use\n")
320 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
322 if (strcmp(vrf_name
, "default") == 0)
323 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
325 vrf
= vrf_lookup_by_name(vrf_name
);
328 vty_out(vty
, "Unable to find vrf you silly head");
329 return CMD_WARNING_CONFIG_FAILED
;
333 label
= MPLS_LABEL_NONE
;
335 vrf_label_add(vrf
->vrf_id
, afi
, label
);
339 DEFPY (remove_routes
,
341 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
342 "Sharp Routing Protocol\n"
343 "Remove some routes\n"
345 "The vrf we would like to remove from if non-default\n"
346 "The NAME of the vrf\n"
349 "Routes to uninstall\n"
351 "Value of instance\n")
354 struct prefix prefix
;
356 sg
.r
.total_routes
= routes
;
357 sg
.r
.removed_routes
= 0;
360 memset(&prefix
, 0, sizeof(prefix
));
362 if (start4
.s_addr
!= 0) {
363 prefix
.family
= AF_INET
;
364 prefix
.prefixlen
= 32;
365 prefix
.u
.prefix4
= start4
;
367 prefix
.family
= AF_INET6
;
368 prefix
.prefixlen
= 128;
369 prefix
.u
.prefix6
= start6
;
372 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
374 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
375 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
379 sg
.r
.inst
= instance
;
380 sg
.r
.vrf_id
= vrf
->vrf_id
;
382 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
388 DEFUN_NOSH (show_debugging_sharpd
,
389 show_debugging_sharpd_cmd
,
390 "show debugging [sharp]",
393 "Sharp Information\n")
395 vty_out(vty
, "Sharp debugging status:\n");
400 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
401 "sharp lsp [update]$update (0-100000)$inlabel\
402 nexthop-group NHGNAME$nhgname\
403 [prefix A.B.C.D/M$pfx\
404 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
405 "Sharp Routing Protocol\n"
408 "The ingress label to use\n"
409 "Use nexthops from a nexthop-group\n"
410 "The nexthop-group name\n"
412 "The v4 prefix to label\n"
413 FRR_IP_REDIST_HELP_STR_ZEBRA
417 struct nexthop_group_cmd
*nhgc
= NULL
;
418 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
419 struct nexthop_group
*backup_nhg
= NULL
;
420 struct prefix p
= {};
424 update_p
= (update
!= NULL
);
426 /* We're offered a v4 prefix */
427 if (pfx
->family
> 0 && type_str
) {
428 p
.family
= pfx
->family
;
429 p
.prefixlen
= pfx
->prefixlen
;
430 p
.u
.prefix4
= pfx
->prefix
;
432 type
= proto_redistnum(AFI_IP
, type_str
);
434 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
437 } else if (pfx
->family
> 0 || type_str
) {
438 vty_out(vty
, "%% Must supply both prefix and type\n");
442 nhgc
= nhgc_find(nhgname
);
444 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
449 if (nhgc
->nhg
.nexthop
== NULL
) {
450 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
454 /* Use group's backup nexthop info if present */
455 if (nhgc
->backup_list_name
[0]) {
456 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
460 "%% Backup group %s not found for group %s\n",
461 nhgc
->backup_list_name
,
465 backup_nhg
= &(backup_nhgc
->nhg
);
468 if (sharp_install_lsps_helper(true /*install*/, update_p
,
469 pfx
->family
> 0 ? &p
: NULL
,
470 type
, instance
, inlabel
,
471 &(nhgc
->nhg
), backup_nhg
) == 0)
474 vty_out(vty
, "%% LSP install failed!\n");
479 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
482 [nexthop-group NHGNAME$nhgname] \
483 [prefix A.B.C.D/M$pfx\
484 " FRR_IP_REDIST_STR_SHARPD
"$type_str [instance (0-255)$instance]]",
485 "Sharp Routing Protocol\n"
488 "The ingress label\n"
489 "Use nexthops from a nexthop-group\n"
490 "The nexthop-group name\n"
491 "Specify a v4 prefix\n"
492 "The v4 prefix to label\n"
493 FRR_IP_REDIST_HELP_STR_SHARPD
497 struct nexthop_group_cmd
*nhgc
= NULL
;
498 struct prefix p
= {};
500 struct nexthop_group
*nhg
= NULL
;
502 /* We're offered a v4 prefix */
503 if (pfx
->family
> 0 && type_str
) {
504 p
.family
= pfx
->family
;
505 p
.prefixlen
= pfx
->prefixlen
;
506 p
.u
.prefix4
= pfx
->prefix
;
508 type
= proto_redistnum(AFI_IP
, type_str
);
510 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
513 } else if (pfx
->family
> 0 || type_str
) {
514 vty_out(vty
, "%% Must supply both prefix and type\n");
519 nhgc
= nhgc_find(nhgname
);
521 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
526 if (nhgc
->nhg
.nexthop
== NULL
) {
527 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
534 if (sharp_install_lsps_helper(false /*!install*/, false,
535 pfx
->family
> 0 ? &p
: NULL
,
536 type
, instance
, inlabel
, nhg
, NULL
) == 0)
539 vty_out(vty
, "%% LSP remove failed!\n");
546 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
547 "Sharp Routing Protocol\n"
548 "Generate bulk log messages for testing\n"
549 "Duration of run (s)\n"
550 "Duration of run (s)\n"
551 "Frequency of bursts (s^-1)\n"
552 "Frequency of bursts (s^-1)\n"
553 "Number of log messages per each burst\n"
554 "Number of log messages per each burst\n")
556 sharp_logpump_run(vty
, duration
, frequency
, burst
);
560 DEFPY (create_session
,
562 "sharp create session (1-1024)",
563 "Sharp Routing Protocol\n"
565 "Create a test session\n"
568 if (sharp_zclient_create(session
) != 0) {
569 vty_out(vty
, "%% Client session error\n");
576 DEFPY (remove_session
,
578 "sharp remove session (1-1024)",
579 "Sharp Routing Protocol\n"
581 "Remove a test session\n"
584 sharp_zclient_delete(session
);
590 "sharp send opaque type (1-255) (1-1000)$count",
592 "Send messages for testing\n"
593 "Send opaque messages\n"
594 "Type code to send\n"
595 "Type code to send\n"
596 "Number of messages to send\n")
598 sharp_opaque_send(type
, 0, 0, 0, count
);
602 DEFPY (send_opaque_unicast
,
603 send_opaque_unicast_cmd
,
604 "sharp send opaque unicast type (1-255) \
605 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
606 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
608 "Send messages for testing\n"
609 "Send opaque messages\n"
610 "Send unicast messages\n"
611 "Type code to send\n"
612 "Type code to send\n"
613 FRR_IP_REDIST_HELP_STR_ZEBRA
618 "Number of messages to send\n")
622 proto
= proto_redistnum(AFI_IP
, proto_str
);
624 sharp_opaque_send(type
, proto
, instance
, session
, count
);
629 DEFPY (send_opaque_reg
,
631 "sharp send opaque <reg$reg | unreg> \
632 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
633 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
635 "Send messages for testing\n"
636 "Send opaque messages\n"
637 "Send opaque registration\n"
638 "Send opaque unregistration\n"
639 FRR_IP_REDIST_HELP_STR_ZEBRA
644 "Opaque sub-type code\n"
645 "Opaque sub-type code\n")
649 proto
= proto_redistnum(AFI_IP
, proto_str
);
651 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
655 DEFPY (neigh_discover
,
657 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
659 "Discover neighbours\n"
660 "Send an ARP/NDP request\n"
662 "v4 Destination address\n"
663 "v6 Destination address\n"
667 struct interface
*ifp
;
668 struct prefix prefix
;
670 memset(&prefix
, 0, sizeof(prefix
));
672 if (dst4
.s_addr
!= 0) {
673 prefix
.family
= AF_INET
;
674 prefix
.prefixlen
= 32;
675 prefix
.u
.prefix4
= dst4
;
677 prefix
.family
= AF_INET6
;
678 prefix
.prefixlen
= 128;
679 prefix
.u
.prefix6
= dst6
;
682 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
684 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
685 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
689 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
691 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
695 sharp_zebra_send_arp(ifp
, &prefix
);
700 void sharp_vty_init(void)
702 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
703 install_element(ENABLE_NODE
, &install_routes_cmd
);
704 install_element(ENABLE_NODE
, &remove_routes_cmd
);
705 install_element(ENABLE_NODE
, &vrf_label_cmd
);
706 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
707 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
708 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
709 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
710 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
711 install_element(ENABLE_NODE
, &logpump_cmd
);
712 install_element(ENABLE_NODE
, &create_session_cmd
);
713 install_element(ENABLE_NODE
, &remove_session_cmd
);
714 install_element(ENABLE_NODE
, &send_opaque_cmd
);
715 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
716 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
717 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
719 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);