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")
151 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
152 vty_out(vty
, "Prefix: %pFX Total: %u %u %u Time: %jd.%ld\n",
153 &sg
.r
.orig_prefix
, sg
.r
.total_routes
, sg
.r
.installed_routes
,
154 sg
.r
.removed_routes
, (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
159 DEFPY (install_routes
,
161 "sharp install routes [vrf NAME$vrf_name]\
162 <A.B.C.D$start4|X:X::X:X$start6>\
163 <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
164 nexthop-group NHGNAME$nexthop_group>\
165 [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
166 (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]",
167 "Sharp routing Protocol\n"
168 "install some routes\n"
169 "Routes to install\n"
170 "The vrf we would like to install into if non-default\n"
171 "The NAME of the vrf\n"
172 "v4 Address to start /32 generation at\n"
173 "v6 Address to start /32 generation at\n"
174 "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
175 "V4 Nexthop address to use\n"
176 "V6 Nexthop address to use\n"
177 "Nexthop-Group to use\n"
178 "The Name of the nexthop-group\n"
179 "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
180 "Backup V4 Nexthop address to use\n"
181 "Backup V6 Nexthop address to use\n"
182 "How many to create\n"
185 "Should we repeat this command\n"
186 "How many times to repeat this command\n"
187 "What opaque data to send down\n"
191 struct prefix prefix
;
195 sg
.r
.total_routes
= routes
;
196 sg
.r
.installed_routes
= 0;
199 sg
.r
.repeat
= rpt
* 2;
203 memset(&prefix
, 0, sizeof(prefix
));
204 memset(&sg
.r
.orig_prefix
, 0, sizeof(sg
.r
.orig_prefix
));
205 memset(&sg
.r
.nhop
, 0, sizeof(sg
.r
.nhop
));
206 memset(&sg
.r
.nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
207 memset(&sg
.r
.backup_nhop
, 0, sizeof(sg
.r
.nhop
));
208 memset(&sg
.r
.backup_nhop_group
, 0, sizeof(sg
.r
.nhop_group
));
210 if (start4
.s_addr
!= INADDR_ANY
) {
211 prefix
.family
= AF_INET
;
212 prefix
.prefixlen
= 32;
213 prefix
.u
.prefix4
= start4
;
215 prefix
.family
= AF_INET6
;
216 prefix
.prefixlen
= 128;
217 prefix
.u
.prefix6
= start6
;
219 sg
.r
.orig_prefix
= prefix
;
222 vrf_name
= VRF_DEFAULT_NAME
;
224 vrf
= vrf_lookup_by_name(vrf_name
);
226 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
231 /* Explicit backup not available with named nexthop-group */
232 if (backup
&& nexthop_group
) {
233 vty_out(vty
, "%% Invalid: cannot specify both nexthop-group and backup\n");
238 struct nexthop_group_cmd
*nhgc
= nhgc_find(nexthop_group
);
241 "Specified Nexthop Group: %s does not exist\n",
246 nhgid
= sharp_nhgroup_get_id(nexthop_group
);
248 sg
.r
.nhop_group
.nexthop
= nhgc
->nhg
.nexthop
;
250 /* Use group's backup nexthop info if present */
251 if (nhgc
->backup_list_name
[0]) {
252 struct nexthop_group_cmd
*bnhgc
=
253 nhgc_find(nhgc
->backup_list_name
);
256 vty_out(vty
, "%% Backup group %s not found for group %s\n",
257 nhgc
->backup_list_name
,
262 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
263 sg
.r
.backup_nhop_group
.nexthop
= bnhgc
->nhg
.nexthop
;
266 if (nexthop4
.s_addr
!= INADDR_ANY
) {
267 sg
.r
.nhop
.gate
.ipv4
= nexthop4
;
268 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV4
;
270 sg
.r
.nhop
.gate
.ipv6
= nexthop6
;
271 sg
.r
.nhop
.type
= NEXTHOP_TYPE_IPV6
;
274 sg
.r
.nhop
.vrf_id
= vrf
->vrf_id
;
275 sg
.r
.nhop_group
.nexthop
= &sg
.r
.nhop
;
278 /* Use single backup nexthop if specified */
280 /* Set flag and index in primary nexthop */
281 SET_FLAG(sg
.r
.nhop
.flags
, NEXTHOP_FLAG_HAS_BACKUP
);
282 sg
.r
.nhop
.backup_num
= 1;
283 sg
.r
.nhop
.backup_idx
[0] = 0;
285 if (backup_nexthop4
.s_addr
!= INADDR_ANY
) {
286 sg
.r
.backup_nhop
.gate
.ipv4
= backup_nexthop4
;
287 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV4
;
289 sg
.r
.backup_nhop
.gate
.ipv6
= backup_nexthop6
;
290 sg
.r
.backup_nhop
.type
= NEXTHOP_TYPE_IPV6
;
293 sg
.r
.backup_nhop
.vrf_id
= vrf
->vrf_id
;
294 sg
.r
.backup_nhop_group
.nexthop
= &sg
.r
.backup_nhop
;
298 strlcpy(sg
.r
.opaque
, opaque
, ZAPI_MESSAGE_OPAQUE_LENGTH
);
300 sg
.r
.opaque
[0] = '\0';
302 sg
.r
.inst
= instance
;
303 sg
.r
.vrf_id
= vrf
->vrf_id
;
305 sharp_install_routes_helper(&prefix
, sg
.r
.vrf_id
, sg
.r
.inst
, nhgid
,
306 &sg
.r
.nhop_group
, &sg
.r
.backup_nhop_group
,
312 DEFPY(vrf_label
, vrf_label_cmd
,
313 "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label",
314 "Sharp Routing Protocol\n"
315 "Give a vrf a label\n"
316 "Pop and forward for IPv4\n"
317 "Pop and forward for IPv6\n"
319 "The label to use, 0 specifies remove the label installed from previous\n"
320 "Specified range to use\n")
323 afi_t afi
= (ipv4
) ? AFI_IP
: AFI_IP6
;
325 if (strcmp(vrf_name
, "default") == 0)
326 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
328 vrf
= vrf_lookup_by_name(vrf_name
);
331 vty_out(vty
, "Unable to find vrf you silly head");
332 return CMD_WARNING_CONFIG_FAILED
;
336 label
= MPLS_LABEL_NONE
;
338 vrf_label_add(vrf
->vrf_id
, afi
, label
);
342 DEFPY (remove_routes
,
344 "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
345 "Sharp Routing Protocol\n"
346 "Remove some routes\n"
348 "The vrf we would like to remove from if non-default\n"
349 "The NAME of the vrf\n"
352 "Routes to uninstall\n"
354 "Value of instance\n")
357 struct prefix prefix
;
359 sg
.r
.total_routes
= routes
;
360 sg
.r
.removed_routes
= 0;
363 memset(&prefix
, 0, sizeof(prefix
));
365 if (start4
.s_addr
!= INADDR_ANY
) {
366 prefix
.family
= AF_INET
;
367 prefix
.prefixlen
= 32;
368 prefix
.u
.prefix4
= start4
;
370 prefix
.family
= AF_INET6
;
371 prefix
.prefixlen
= 128;
372 prefix
.u
.prefix6
= start6
;
375 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
377 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
378 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
382 sg
.r
.inst
= instance
;
383 sg
.r
.vrf_id
= vrf
->vrf_id
;
385 sharp_remove_routes_helper(&prefix
, sg
.r
.vrf_id
,
391 DEFUN_NOSH (show_debugging_sharpd
,
392 show_debugging_sharpd_cmd
,
393 "show debugging [sharp]",
396 "Sharp Information\n")
398 vty_out(vty
, "Sharp debugging status:\n");
403 DEFPY (sharp_lsp_prefix_v4
, sharp_lsp_prefix_v4_cmd
,
404 "sharp lsp [update]$update (0-100000)$inlabel\
405 nexthop-group NHGNAME$nhgname\
406 [prefix A.B.C.D/M$pfx\
407 " FRR_IP_REDIST_STR_ZEBRA
"$type_str [instance (0-255)$instance]]",
408 "Sharp Routing Protocol\n"
411 "The ingress label to use\n"
412 "Use nexthops from a nexthop-group\n"
413 "The nexthop-group name\n"
415 "The v4 prefix to label\n"
416 FRR_IP_REDIST_HELP_STR_ZEBRA
420 struct nexthop_group_cmd
*nhgc
= NULL
;
421 struct nexthop_group_cmd
*backup_nhgc
= NULL
;
422 struct nexthop_group
*backup_nhg
= NULL
;
423 struct prefix p
= {};
427 update_p
= (update
!= NULL
);
429 /* We're offered a v4 prefix */
430 if (pfx
->family
> 0 && type_str
) {
431 p
.family
= pfx
->family
;
432 p
.prefixlen
= pfx
->prefixlen
;
433 p
.u
.prefix4
= pfx
->prefix
;
435 type
= proto_redistnum(AFI_IP
, type_str
);
437 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
440 } else if (pfx
->family
> 0 || type_str
) {
441 vty_out(vty
, "%% Must supply both prefix and type\n");
445 nhgc
= nhgc_find(nhgname
);
447 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
452 if (nhgc
->nhg
.nexthop
== NULL
) {
453 vty_out(vty
, "%% Nexthop-group '%s' is empty\n", nhgname
);
457 /* Use group's backup nexthop info if present */
458 if (nhgc
->backup_list_name
[0]) {
459 backup_nhgc
= nhgc_find(nhgc
->backup_list_name
);
463 "%% Backup group %s not found for group %s\n",
464 nhgc
->backup_list_name
,
468 backup_nhg
= &(backup_nhgc
->nhg
);
471 if (sharp_install_lsps_helper(true /*install*/, update_p
,
472 pfx
->family
> 0 ? &p
: NULL
,
473 type
, instance
, inlabel
,
474 &(nhgc
->nhg
), backup_nhg
) == 0)
477 vty_out(vty
, "%% LSP install failed!\n");
482 DEFPY(sharp_remove_lsp_prefix_v4
, sharp_remove_lsp_prefix_v4_cmd
,
485 [nexthop-group NHGNAME$nhgname] \
486 [prefix A.B.C.D/M$pfx\
487 " FRR_IP_REDIST_STR_SHARPD
"$type_str [instance (0-255)$instance]]",
488 "Sharp Routing Protocol\n"
491 "The ingress label\n"
492 "Use nexthops from a nexthop-group\n"
493 "The nexthop-group name\n"
494 "Specify a v4 prefix\n"
495 "The v4 prefix to label\n"
496 FRR_IP_REDIST_HELP_STR_SHARPD
500 struct nexthop_group_cmd
*nhgc
= NULL
;
501 struct prefix p
= {};
503 struct nexthop_group
*nhg
= NULL
;
505 /* We're offered a v4 prefix */
506 if (pfx
->family
> 0 && type_str
) {
507 p
.family
= pfx
->family
;
508 p
.prefixlen
= pfx
->prefixlen
;
509 p
.u
.prefix4
= pfx
->prefix
;
511 type
= proto_redistnum(AFI_IP
, type_str
);
513 vty_out(vty
, "%% Unknown route type '%s'\n", type_str
);
516 } else if (pfx
->family
> 0 || type_str
) {
517 vty_out(vty
, "%% Must supply both prefix and type\n");
522 nhgc
= nhgc_find(nhgname
);
524 vty_out(vty
, "%% Nexthop-group '%s' does not exist\n",
529 if (nhgc
->nhg
.nexthop
== NULL
) {
530 vty_out(vty
, "%% Nexthop-group '%s' is empty\n",
537 if (sharp_install_lsps_helper(false /*!install*/, false,
538 pfx
->family
> 0 ? &p
: NULL
,
539 type
, instance
, inlabel
, nhg
, NULL
) == 0)
542 vty_out(vty
, "%% LSP remove failed!\n");
549 "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)",
550 "Sharp Routing Protocol\n"
551 "Generate bulk log messages for testing\n"
552 "Duration of run (s)\n"
553 "Duration of run (s)\n"
554 "Frequency of bursts (s^-1)\n"
555 "Frequency of bursts (s^-1)\n"
556 "Number of log messages per each burst\n"
557 "Number of log messages per each burst\n")
559 sharp_logpump_run(vty
, duration
, frequency
, burst
);
563 DEFPY (create_session
,
565 "sharp create session (1-1024)",
566 "Sharp Routing Protocol\n"
568 "Create a test session\n"
571 if (sharp_zclient_create(session
) != 0) {
572 vty_out(vty
, "%% Client session error\n");
579 DEFPY (remove_session
,
581 "sharp remove session (1-1024)",
582 "Sharp Routing Protocol\n"
584 "Remove a test session\n"
587 sharp_zclient_delete(session
);
593 "sharp send opaque type (1-255) (1-1000)$count",
595 "Send messages for testing\n"
596 "Send opaque messages\n"
597 "Type code to send\n"
598 "Type code to send\n"
599 "Number of messages to send\n")
601 sharp_opaque_send(type
, 0, 0, 0, count
);
605 DEFPY (send_opaque_unicast
,
606 send_opaque_unicast_cmd
,
607 "sharp send opaque unicast type (1-255) \
608 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
609 [{instance (0-1000) | session (1-1000)}] (1-1000)$count",
611 "Send messages for testing\n"
612 "Send opaque messages\n"
613 "Send unicast messages\n"
614 "Type code to send\n"
615 "Type code to send\n"
616 FRR_IP_REDIST_HELP_STR_ZEBRA
621 "Number of messages to send\n")
625 proto
= proto_redistnum(AFI_IP
, proto_str
);
627 sharp_opaque_send(type
, proto
, instance
, session
, count
);
632 DEFPY (send_opaque_reg
,
634 "sharp send opaque <reg$reg | unreg> \
635 " FRR_IP_REDIST_STR_ZEBRA
"$proto_str \
636 [{instance (0-1000) | session (1-1000)}] type (1-1000)",
638 "Send messages for testing\n"
639 "Send opaque messages\n"
640 "Send opaque registration\n"
641 "Send opaque unregistration\n"
642 FRR_IP_REDIST_HELP_STR_ZEBRA
647 "Opaque sub-type code\n"
648 "Opaque sub-type code\n")
652 proto
= proto_redistnum(AFI_IP
, proto_str
);
654 sharp_opaque_reg_send((reg
!= NULL
), proto
, instance
, session
, type
);
658 DEFPY (neigh_discover
,
660 "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
662 "Discover neighbours\n"
663 "Send an ARP/NDP request\n"
665 "v4 Destination address\n"
666 "v6 Destination address\n"
670 struct interface
*ifp
;
671 struct prefix prefix
;
673 memset(&prefix
, 0, sizeof(prefix
));
675 if (dst4
.s_addr
!= INADDR_ANY
) {
676 prefix
.family
= AF_INET
;
677 prefix
.prefixlen
= 32;
678 prefix
.u
.prefix4
= dst4
;
680 prefix
.family
= AF_INET6
;
681 prefix
.prefixlen
= 128;
682 prefix
.u
.prefix6
= dst6
;
685 vrf
= vrf_lookup_by_name(vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
687 vty_out(vty
, "The vrf NAME specified: %s does not exist\n",
688 vrf_name
? vrf_name
: VRF_DEFAULT_NAME
);
692 ifp
= if_lookup_by_name_vrf(ifname
, vrf
);
694 vty_out(vty
, "%% Can't find interface %s\n", ifname
);
698 sharp_zebra_send_arp(ifp
, &prefix
);
703 void sharp_vty_init(void)
705 install_element(ENABLE_NODE
, &install_routes_data_dump_cmd
);
706 install_element(ENABLE_NODE
, &install_routes_cmd
);
707 install_element(ENABLE_NODE
, &remove_routes_cmd
);
708 install_element(ENABLE_NODE
, &vrf_label_cmd
);
709 install_element(ENABLE_NODE
, &sharp_nht_data_dump_cmd
);
710 install_element(ENABLE_NODE
, &watch_nexthop_v6_cmd
);
711 install_element(ENABLE_NODE
, &watch_nexthop_v4_cmd
);
712 install_element(ENABLE_NODE
, &sharp_lsp_prefix_v4_cmd
);
713 install_element(ENABLE_NODE
, &sharp_remove_lsp_prefix_v4_cmd
);
714 install_element(ENABLE_NODE
, &logpump_cmd
);
715 install_element(ENABLE_NODE
, &create_session_cmd
);
716 install_element(ENABLE_NODE
, &remove_session_cmd
);
717 install_element(ENABLE_NODE
, &send_opaque_cmd
);
718 install_element(ENABLE_NODE
, &send_opaque_unicast_cmd
);
719 install_element(ENABLE_NODE
, &send_opaque_reg_cmd
);
720 install_element(ENABLE_NODE
, &neigh_discover_cmd
);
722 install_element(ENABLE_NODE
, &show_debugging_sharpd_cmd
);