3 * Copyright (C) 2018 Cumulus Networks, Inc.
6 * FRR is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * FRR is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "nexthop_group.h"
32 #include "pbrd/pbr_nht.h"
33 #include "pbrd/pbr_map.h"
34 #include "pbrd/pbr_zebra.h"
35 #include "pbrd/pbr_vty.h"
36 #include "pbrd/pbr_debug.h"
37 #ifndef VTYSH_EXTRACT_PL
38 #include "pbrd/pbr_vty_clippy.c"
41 DEFUN_NOSH(pbr_map
, pbr_map_cmd
, "pbr-map WORD seq (1-1000)",
42 "Create pbr-map or enter pbr-map command mode\n"
43 "The name of the PBR MAP\n"
44 "Sequence to insert in existing pbr-map entry\n"
47 const char *pbrm_name
= argv
[1]->arg
;
48 uint32_t seqno
= atoi(argv
[3]->arg
);
49 struct pbr_map_sequence
*pbrms
;
51 pbrms
= pbrms_get(pbrm_name
, seqno
);
52 VTY_PUSH_CONTEXT(PBRMAP_NODE
, pbrms
);
57 DEFUN_NOSH(no_pbr_map
, no_pbr_map_cmd
, "no pbr-map WORD [seq (1-65535)]",
60 "The name of the PBR MAP\n"
61 "Sequence to delete from existing pbr-map entry\n"
64 const char *pbrm_name
= argv
[2]->arg
;
66 struct pbr_map
*pbrm
= pbrm_find(pbrm_name
);
67 struct pbr_map_sequence
*pbrms
;
68 struct listnode
*node
, *next_node
;
71 seqno
= atoi(argv
[4]->arg
);
74 vty_out(vty
, "pbr-map %s not found\n", pbrm_name
);
78 for (ALL_LIST_ELEMENTS(pbrm
->seqnumbers
, node
, next_node
, pbrms
)) {
79 if (seqno
&& pbrms
->seqno
!= seqno
)
82 pbr_map_delete(pbrms
);
88 DEFPY(pbr_map_match_src
, pbr_map_match_src_cmd
,
89 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
91 "Match the rest of the command\n"
92 "Choose the src ip or ipv6 prefix to use\n"
96 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
98 pbrms
->family
= prefix
->family
;
101 if (prefix_same(pbrms
->src
, prefix
))
105 pbrms
->src
= prefix_new();
106 prefix_copy(pbrms
->src
, prefix
);
108 prefix_free(pbrms
->src
);
112 pbr_map_check(pbrms
);
117 DEFPY(pbr_map_match_dst
, pbr_map_match_dst_cmd
,
118 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
120 "Match the rest of the command\n"
121 "Choose the src ip or ipv6 prefix to use\n"
125 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
127 pbrms
->family
= prefix
->family
;
130 if (prefix_same(pbrms
->dst
, prefix
))
134 pbrms
->dst
= prefix_new();
135 prefix_copy(pbrms
->dst
, prefix
);
137 prefix_free(pbrms
->dst
);
141 pbr_map_check(pbrms
);
146 DEFPY(pbr_map_nexthop_group
, pbr_map_nexthop_group_cmd
,
147 "[no] set nexthop-group NAME$name",
149 "Set for the PBR-MAP\n"
150 "nexthop-group to use\n"
151 "The name of the nexthop-group\n")
153 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
154 struct nexthop_group_cmd
*nhgc
;
158 "A `set nexthop XX` command already exists, please remove that first\n");
159 return CMD_WARNING_CONFIG_FAILED
;
162 nhgc
= nhgc_find(name
);
164 vty_out(vty
, "Specified nexthop-group %s does not exist\n",
166 vty_out(vty
, "PBR-MAP will not be applied until it is created\n");
170 if (pbrms
->nhgrp_name
&& strcmp(name
, pbrms
->nhgrp_name
) == 0)
171 pbr_map_delete_nexthop_group(pbrms
);
174 "Nexthop Group specified: %s does not exist to remove",
176 return CMD_WARNING_CONFIG_FAILED
;
179 if (pbrms
->nhgrp_name
) {
180 if (strcmp(name
, pbrms
->nhgrp_name
) != 0) {
182 "Please delete current nexthop group before modifying current one");
183 return CMD_WARNING_CONFIG_FAILED
;
188 pbrms
->nhgrp_name
= XSTRDUP(MTYPE_TMP
, name
);
189 pbr_map_check(pbrms
);
195 DEFPY(pbr_map_nexthop
, pbr_map_nexthop_cmd
,
196 "[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
198 "Set for the PBR-MAP\n"
199 "Specify one of the nexthops in this map\n"
203 "If the nexthop is in a different vrf tell us\n"
204 "The nexthop-vrf Name\n")
206 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
211 if (pbrms
->nhgrp_name
) {
213 "Please unconfigure the nexthop group before adding an individual nexthop");
214 return CMD_WARNING_CONFIG_FAILED
;
218 vrf
= vrf_lookup_by_name(name
);
220 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
223 vty_out(vty
, "Specified: %s is non-existent\n", name
);
224 return CMD_WARNING_CONFIG_FAILED
;
227 memset(&nhop
, 0, sizeof(nhop
));
228 nhop
.vrf_id
= vrf
->vrf_id
;
230 if (addr
->sa
.sa_family
== AF_INET
) {
231 nhop
.gate
.ipv4
.s_addr
= addr
->sin
.sin_addr
.s_addr
;
233 nhop
.type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
234 nhop
.ifindex
= ifname2ifindex(intf
, vrf
->vrf_id
);
235 if (nhop
.ifindex
== IFINDEX_INTERNAL
) {
237 "Specified Intf %s does not exist in vrf: %s\n",
239 return CMD_WARNING_CONFIG_FAILED
;
242 nhop
.type
= NEXTHOP_TYPE_IPV4
;
244 memcpy(&nhop
.gate
.ipv6
, &addr
->sin6
.sin6_addr
, 16);
246 nhop
.type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
247 nhop
.ifindex
= ifname2ifindex(intf
, vrf
->vrf_id
);
248 if (nhop
.ifindex
== IFINDEX_INTERNAL
) {
250 "Specified Intf %s does not exist in vrf: %s\n",
252 return CMD_WARNING_CONFIG_FAILED
;
255 if (IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
)) {
257 "Specified a v6 LL with no interface, rejecting\n");
258 return CMD_WARNING_CONFIG_FAILED
;
260 nhop
.type
= NEXTHOP_TYPE_IPV6
;
265 nh
= nexthop_exists(pbrms
->nhg
, &nhop
);
270 vty_out(vty
, "No nexthops to delete");
271 return CMD_WARNING_CONFIG_FAILED
;
274 pbrms
->nhg
= nexthop_group_new();
275 pbrms
->internal_nhg_name
=
277 pbr_nht_nexthop_make_name(pbrms
->parent
->name
,
286 pbr_nht_delete_individual_nexthop(pbrms
);
289 if (pbrms
->nhg
->nexthop
) {
291 "If you would like more than one nexthop please use nexthop-groups");
292 return CMD_WARNING_CONFIG_FAILED
;
295 /* must be adding new nexthop since !no and !nexthop_exists */
298 memcpy(nh
, &nhop
, sizeof(nhop
));
299 nexthop_add(&pbrms
->nhg
->nexthop
, nh
);
301 pbr_nht_add_individual_nexthop(pbrms
);
302 pbr_map_check(pbrms
);
310 "[no] pbr-policy NAME$mapname",
313 "Name of the pbr-map to apply\n")
315 VTY_DECLVAR_CONTEXT(interface
, ifp
);
316 struct pbr_map
*pbrm
, *old_pbrm
;
317 struct pbr_interface
*pbr_ifp
= ifp
->info
;
319 pbrm
= pbrm_find(mapname
);
323 * Some one could have fat fingered the interface
326 pbr_ifp
= pbr_if_new(ifp
);
330 if (strcmp(pbr_ifp
->mapname
, mapname
) == 0) {
331 strcpy(pbr_ifp
->mapname
, "");
334 pbr_map_interface_delete(pbrm
, ifp
);
337 if (strcmp(pbr_ifp
->mapname
, "") == 0) {
338 strcpy(pbr_ifp
->mapname
, mapname
);
341 pbr_map_add_interface(pbrm
, ifp
);
343 if (!(strcmp(pbr_ifp
->mapname
, mapname
) == 0)) {
344 old_pbrm
= pbrm_find(pbr_ifp
->mapname
);
346 pbr_map_interface_delete(old_pbrm
, ifp
);
347 strcpy(pbr_ifp
->mapname
, mapname
);
349 pbr_map_add_interface(pbrm
, ifp
);
359 "show pbr [json$json]",
361 "Policy Based Routing\n"
364 pbr_nht_write_table_range(vty
);
365 pbr_nht_write_rule_range(vty
);
372 "show pbr map [NAME$name] [detail$detail] [json$json]",
374 "Policy Based Routing\n"
377 "Detailed information\n"
380 struct pbr_map_sequence
*pbrms
;
381 struct pbr_map
*pbrm
;
382 struct listnode
*node
;
383 char buf
[PREFIX_STRLEN
];
386 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
387 if (name
&& strcmp(name
, pbrm
->name
) != 0)
390 vty_out(vty
, " pbr-map %s valid: %d\n", pbrm
->name
,
393 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
)) {
395 pbr_map_reason_string(pbrms
->reason
, rbuf
,
398 " Seq: %u rule: %u Installed: %" PRIu64
"(%u) Reason: %s\n",
399 pbrms
->seqno
, pbrms
->ruleno
, pbrms
->installed
,
400 pbrms
->unique
, pbrms
->reason
? rbuf
: "Valid");
403 vty_out(vty
, "\tSRC Match: %s\n",
404 prefix2str(pbrms
->src
, buf
,
407 vty_out(vty
, "\tDST Match: %s\n",
408 prefix2str(pbrms
->dst
, buf
,
411 if (pbrms
->nhgrp_name
) {
413 "\tNexthop-Group: %s(%u) Installed: %u(%d)\n",
415 pbr_nht_get_table(pbrms
->nhgrp_name
),
416 pbrms
->nhs_installed
,
417 pbr_nht_get_installed(
419 } else if (pbrms
->nhg
) {
421 nexthop_group_write_nexthop(
422 vty
, pbrms
->nhg
->nexthop
);
424 "\tInstalled: %u(%d) Tableid: %d\n",
425 pbrms
->nhs_installed
,
426 pbr_nht_get_installed(
427 pbrms
->internal_nhg_name
),
429 pbrms
->internal_nhg_name
));
432 "\tNexthop-Group: Unknown Installed: 0(0)\n");
439 DEFPY(show_pbr_nexthop_group
,
440 show_pbr_nexthop_group_cmd
,
441 "show pbr nexthop-groups [WORD$word]",
443 "Policy Based Routing\n"
445 "Optional Name of the nexthop group\n")
447 pbr_nht_show_nexthop_group(vty
, word
);
452 DEFPY (show_pbr_interface
,
453 show_pbr_interface_cmd
,
454 "show pbr interface [NAME$name] [json$json]",
456 "Policy Based Routing\n"
458 "PBR Interface Name\n"
461 struct interface
*ifp
;
463 struct pbr_interface
*pbr_ifp
;
465 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
466 FOR_ALL_INTERFACES(vrf
, ifp
) {
467 struct pbr_map
*pbrm
;
472 if (name
&& strcmp(ifp
->name
, name
) != 0)
477 if (strcmp(pbr_ifp
->mapname
, "") == 0)
480 pbrm
= pbrm_find(pbr_ifp
->mapname
);
481 vty_out(vty
, " %s(%d) with pbr-policy %s", ifp
->name
,
482 ifp
->ifindex
, pbr_ifp
->mapname
);
484 vty_out(vty
, " (map doesn't exist)");
492 static struct cmd_node interface_node
= {
493 INTERFACE_NODE
, "%s(config-if)# ", 1 /* vtysh ? yes */
496 static int pbr_interface_config_write(struct vty
*vty
)
498 struct interface
*ifp
;
501 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
502 FOR_ALL_INTERFACES (vrf
, ifp
) {
503 if (vrf
->vrf_id
== VRF_DEFAULT
)
504 vty_frame(vty
, "interface %s\n", ifp
->name
);
506 vty_frame(vty
, "interface %s vrf %s\n",
507 ifp
->name
, vrf
->name
);
509 pbr_map_write_interfaces(vty
, ifp
);
511 vty_endframe(vty
, "!\n");
518 /* PBR map node structure. */
519 static struct cmd_node pbr_map_node
= {PBRMAP_NODE
, "%s(config-pbr-map)# ", 1};
521 static int pbr_vty_map_config_write_sequence(struct vty
*vty
,
522 struct pbr_map
*pbrm
,
523 struct pbr_map_sequence
*pbrms
)
525 char buff
[PREFIX_STRLEN
];
527 vty_out(vty
, "pbr-map %s seq %u\n", pbrm
->name
, pbrms
->seqno
);
530 vty_out(vty
, " match src-ip %s\n",
531 prefix2str(pbrms
->src
, buff
, sizeof(buff
)));
534 vty_out(vty
, " match dst-ip %s\n",
535 prefix2str(pbrms
->dst
, buff
, sizeof(buff
)));
537 if (pbrms
->nhgrp_name
)
538 vty_out(vty
, " set nexthop-group %s\n", pbrms
->nhgrp_name
);
541 vty_out(vty
, " set ");
542 nexthop_group_write_nexthop(vty
, pbrms
->nhg
->nexthop
);
549 static int pbr_vty_map_config_write(struct vty
*vty
)
551 struct pbr_map
*pbrm
;
553 pbr_nht_write_table_range(vty
);
554 pbr_nht_write_rule_range(vty
);
556 RB_FOREACH(pbrm
, pbr_map_entry_head
, &pbr_maps
) {
557 struct pbr_map_sequence
*pbrms
;
558 struct listnode
*node
;
560 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
561 pbr_vty_map_config_write_sequence(vty
, pbrm
, pbrms
);
567 void pbr_vty_init(void)
569 install_node(&interface_node
,
570 pbr_interface_config_write
);
573 install_node(&pbr_map_node
,
574 pbr_vty_map_config_write
);
576 install_default(PBRMAP_NODE
);
578 install_element(CONFIG_NODE
, &pbr_map_cmd
);
579 install_element(CONFIG_NODE
, &no_pbr_map_cmd
);
580 install_element(INTERFACE_NODE
, &pbr_policy_cmd
);
581 install_element(PBRMAP_NODE
, &pbr_map_match_src_cmd
);
582 install_element(PBRMAP_NODE
, &pbr_map_match_dst_cmd
);
583 install_element(PBRMAP_NODE
, &pbr_map_nexthop_group_cmd
);
584 install_element(PBRMAP_NODE
, &pbr_map_nexthop_cmd
);
585 install_element(VIEW_NODE
, &show_pbr_cmd
);
586 install_element(VIEW_NODE
, &show_pbr_map_cmd
);
587 install_element(VIEW_NODE
, &show_pbr_interface_cmd
);
588 install_element(VIEW_NODE
, &show_pbr_nexthop_group_cmd
);
590 pbr_debug_init_vty();