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"
28 #include "nexthop_group_private.h"
34 #include "pbrd/pbr_nht.h"
35 #include "pbrd/pbr_map.h"
36 #include "pbrd/pbr_zebra.h"
37 #include "pbrd/pbr_vty.h"
38 #include "pbrd/pbr_debug.h"
39 #ifndef VTYSH_EXTRACT_PL
40 #include "pbrd/pbr_vty_clippy.c"
43 DEFUN_NOSH(pbr_map
, pbr_map_cmd
, "pbr-map PBRMAP seq (1-700)",
44 "Create pbr-map or enter pbr-map command mode\n"
45 "The name of the PBR MAP\n"
46 "Sequence to insert in existing pbr-map entry\n"
49 const char *pbrm_name
= argv
[1]->arg
;
50 uint32_t seqno
= atoi(argv
[3]->arg
);
51 struct pbr_map_sequence
*pbrms
;
53 pbrms
= pbrms_get(pbrm_name
, seqno
);
54 VTY_PUSH_CONTEXT(PBRMAP_NODE
, pbrms
);
59 DEFUN_NOSH(no_pbr_map
, no_pbr_map_cmd
, "no pbr-map PBRMAP [seq (1-700)]",
62 "The name of the PBR MAP\n"
63 "Sequence to delete from existing pbr-map entry\n"
66 const char *pbrm_name
= argv
[2]->arg
;
68 struct pbr_map
*pbrm
= pbrm_find(pbrm_name
);
69 struct pbr_map_sequence
*pbrms
;
70 struct listnode
*node
, *next_node
;
73 seqno
= atoi(argv
[4]->arg
);
76 vty_out(vty
, "pbr-map %s not found\n", pbrm_name
);
80 for (ALL_LIST_ELEMENTS(pbrm
->seqnumbers
, node
, next_node
, pbrms
)) {
81 if (seqno
&& pbrms
->seqno
!= seqno
)
84 pbr_map_delete(pbrms
);
90 DEFPY(pbr_set_table_range
,
91 pbr_set_table_range_cmd
,
92 "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
94 "Set table ID range\n"
95 "Set table ID range\n"
96 "Lower bound for table ID range\n"
97 "Upper bound for table ID range\n")
99 /* upper bound is 2^32 - 2^10 */
100 int ret
= CMD_WARNING
;
101 const int minrange
= 1000;
103 /* validate given bounds */
105 vty_out(vty
, "%% Lower bound must be less than upper bound\n");
106 else if (ub
- lb
< minrange
)
107 vty_out(vty
, "%% Range breadth must be at least %d\n", minrange
);
110 pbr_nht_set_tableid_range((uint32_t) lb
, (uint32_t) ub
);
116 DEFPY(no_pbr_set_table_range
, no_pbr_set_table_range_cmd
,
117 "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
120 "Set table ID range\n"
121 "Set table ID range\n"
122 "Lower bound for table ID range\n"
123 "Upper bound for table ID range\n")
125 pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID
,
126 PBR_NHT_DEFAULT_HIGH_TABLEID
);
130 DEFPY(pbr_map_match_src
, pbr_map_match_src_cmd
,
131 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
133 "Match the rest of the command\n"
134 "Choose the src ip or ipv6 prefix to use\n"
138 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
140 if (pbrms
->dst
&& pbrms
->family
&& prefix
->family
!= pbrms
->family
) {
141 vty_out(vty
, "Cannot mismatch families within match src/dst\n");
142 return CMD_WARNING_CONFIG_FAILED
;
145 pbrms
->family
= prefix
->family
;
149 if (prefix_same(pbrms
->src
, prefix
))
152 pbrms
->src
= prefix_new();
154 prefix_copy(pbrms
->src
, prefix
);
156 prefix_free(&pbrms
->src
);
158 pbr_map_check(pbrms
, true);
163 DEFPY(pbr_map_match_dst
, pbr_map_match_dst_cmd
,
164 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
166 "Match the rest of the command\n"
167 "Choose the dst ip or ipv6 prefix to use\n"
171 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
173 if (pbrms
->src
&& pbrms
->family
&& prefix
->family
!= pbrms
->family
) {
174 vty_out(vty
, "Cannot mismatch families within match src/dst\n");
175 return CMD_WARNING_CONFIG_FAILED
;
178 pbrms
->family
= prefix
->family
;
182 if (prefix_same(pbrms
->dst
, prefix
))
185 pbrms
->dst
= prefix_new();
187 prefix_copy(pbrms
->dst
, prefix
);
189 prefix_free(&pbrms
->dst
);
191 pbr_map_check(pbrms
, true);
196 DEFPY(pbr_map_match_ip_proto
, pbr_map_match_ip_proto_cmd
,
197 "[no] match ip-protocol [tcp|udp]$ip_proto",
199 "Match the rest of the command\n"
200 "Choose an ip-protocol\n"
201 "Match on tcp flows\n"
202 "Match on udp flows\n")
204 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
208 p
= getprotobyname(ip_proto
);
210 vty_out(vty
, "Unable to convert %s to proto id\n",
215 pbrms
->ip_proto
= p
->p_proto
;
222 DEFPY(pbr_map_match_src_port
, pbr_map_match_src_port_cmd
,
223 "[no] match src-port (1-65535)$port",
225 "Match the rest of the command\n"
226 "Choose the source port to use\n"
229 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
232 if (pbrms
->src_prt
== port
)
235 pbrms
->src_prt
= port
;
239 pbr_map_check(pbrms
, true);
244 DEFPY(pbr_map_match_dst_port
, pbr_map_match_dst_port_cmd
,
245 "[no] match dst-port (1-65535)$port",
247 "Match the rest of the command\n"
248 "Choose the destination port to use\n"
249 "The Destination Port\n")
251 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
254 if (pbrms
->dst_prt
== port
)
257 pbrms
->dst_prt
= port
;
261 pbr_map_check(pbrms
, true);
266 DEFPY(pbr_map_match_dscp
, pbr_map_match_dscp_cmd
,
267 "[no] match dscp DSCP$dscp",
269 "Match the rest of the command\n"
270 "Match based on IP DSCP field\n"
271 "DSCP value (below 64) or standard codepoint name\n")
273 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
277 /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
278 bool isANumber
= true;
279 for (int i
= 0; i
< (int)strlen(dscp
); i
++) {
280 /* Letters are not numbers */
281 if (!isdigit(dscp
[i
]))
284 /* Lowercase the dscp enum (if needed) */
285 if (isupper(dscp
[i
]))
286 dscpname
[i
] = tolower(dscp
[i
]);
288 dscpname
[i
] = dscp
[i
];
290 dscpname
[strlen(dscp
)] = '\0';
293 /* dscp passed is a regular number */
294 long dscpAsNum
= strtol(dscp
, NULL
, 0);
296 if (dscpAsNum
> PBR_DSFIELD_DSCP
>> 2) {
297 /* Refuse to install on overflow */
298 vty_out(vty
, "dscp (%s) must be less than 64\n", dscp
);
299 return CMD_WARNING_CONFIG_FAILED
;
303 /* check dscp if it is an enum like cs0 */
304 rawDscp
= pbr_map_decode_dscp_enum(dscpname
);
305 if (rawDscp
> PBR_DSFIELD_DSCP
) {
306 vty_out(vty
, "Invalid dscp value: %s\n", dscpname
);
307 return CMD_WARNING_CONFIG_FAILED
;
312 if (((pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2) == rawDscp
)
315 /* Set the DSCP bits of the DSField */
317 (pbrms
->dsfield
& ~PBR_DSFIELD_DSCP
) | (rawDscp
<< 2);
319 pbrms
->dsfield
&= ~PBR_DSFIELD_DSCP
;
322 pbr_map_check(pbrms
, true);
327 DEFPY(pbr_map_match_ecn
, pbr_map_match_ecn_cmd
,
328 "[no] match ecn (0-3)$ecn",
330 "Match the rest of the command\n"
331 "Match based on IP ECN field\n"
332 "Explicit Congestion Notification\n")
334 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
337 if ((pbrms
->dsfield
& PBR_DSFIELD_ECN
) == ecn
)
340 /* Set the ECN bits of the DSField */
341 pbrms
->dsfield
= (pbrms
->dsfield
& ~PBR_DSFIELD_ECN
) | ecn
;
343 pbrms
->dsfield
&= ~PBR_DSFIELD_ECN
;
346 pbr_map_check(pbrms
, true);
351 DEFPY(pbr_map_match_mark
, pbr_map_match_mark_cmd
,
352 "[no] match mark (1-4294967295)$mark",
354 "Match the rest of the command\n"
355 "Choose the mark value to use\n"
358 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
361 vty_out(vty
, "pbr marks are not supported on this platform");
362 return CMD_WARNING_CONFIG_FAILED
;
367 if (pbrms
->mark
== (uint32_t)mark
)
370 pbrms
->mark
= (uint32_t)mark
;
374 pbr_map_check(pbrms
, true);
379 static void pbrms_clear_set_vrf_config(struct pbr_map_sequence
*pbrms
)
381 if (pbrms
->vrf_lookup
|| pbrms
->vrf_unchanged
) {
382 pbr_map_delete_vrf(pbrms
);
383 pbrms
->vrf_name
[0] = '\0';
384 pbrms
->vrf_lookup
= false;
385 pbrms
->vrf_unchanged
= false;
389 static void pbrms_clear_set_nhg_config(struct pbr_map_sequence
*pbrms
)
391 if (pbrms
->nhgrp_name
)
392 pbr_map_delete_nexthops(pbrms
);
395 static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence
*pbrms
)
398 pbr_nht_delete_individual_nexthop(pbrms
);
401 static void pbrms_clear_set_config(struct pbr_map_sequence
*pbrms
)
403 pbrms_clear_set_vrf_config(pbrms
);
404 pbrms_clear_set_nhg_config(pbrms
);
405 pbrms_clear_set_nexthop_config(pbrms
);
407 pbrms
->nhs_installed
= false;
411 DEFPY(pbr_map_action_queue_id
, pbr_map_action_queue_id_cmd
,
412 "[no] set queue-id <(1-65535)$queue_id>",
414 "Set the rest of the command\n"
415 "Set based on egress port queue id\n"
416 "A valid value in range 1..65535 \n")
418 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
421 pbrms
->action_queue_id
= queue_id
;
422 else if ((uint32_t)queue_id
== pbrms
->action_queue_id
)
423 pbrms
->action_queue_id
= PBR_MAP_UNDEFINED_QUEUE_ID
;
425 pbr_map_check(pbrms
, true);
430 DEFPY(pbr_map_action_pcp
, pbr_map_action_pcp_cmd
, "[no] set pcp <(0-7)$pcp>",
432 "Set the rest of the command\n"
433 "Set based on 802.1p Priority Code Point (PCP) value\n"
434 "A valid value in range 0..7\n")
436 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
439 pbrms
->action_pcp
= pcp
;
440 else if (pcp
== pbrms
->action_pcp
)
441 pbrms
->action_pcp
= 0;
443 pbr_map_check(pbrms
, true);
448 DEFPY(pbr_map_action_vlan_id
, pbr_map_action_vlan_id_cmd
,
449 "[no] set vlan <(1-4094)$vlan_id>",
451 "Set the rest of the command\n"
452 "Set action for VLAN tagging\n"
453 "A valid value in range 1..4094\n")
455 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
458 pbrms
->action_vlan_id
= vlan_id
;
459 else if (pbrms
->action_vlan_id
== vlan_id
)
460 pbrms
->action_vlan_id
= 0;
462 pbr_map_check(pbrms
, true);
467 DEFPY(pbr_map_action_strip_vlan
, pbr_map_action_strip_vlan_cmd
,
470 "Strip the vlan tags from frame\n"
471 "Strip any inner vlan tag \n")
473 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
476 pbrms
->action_vlan_flags
= PBR_MAP_STRIP_INNER_ANY
;
478 pbrms
->action_vlan_flags
= 0;
480 pbr_map_check(pbrms
, true);
486 DEFPY(pbr_map_nexthop_group
, pbr_map_nexthop_group_cmd
,
487 "set nexthop-group NHGNAME$name",
488 "Set for the PBR-MAP\n"
489 "nexthop-group to use\n"
490 "The name of the nexthop-group\n")
492 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
493 struct nexthop_group_cmd
*nhgc
;
495 nhgc
= nhgc_find(name
);
497 vty_out(vty
, "Specified nexthop-group %s does not exist\n",
500 "PBR-MAP will not be applied until it is created\n");
503 if (pbrms
->nhgrp_name
&& strcmp(name
, pbrms
->nhgrp_name
) == 0)
506 /* This is new/replacement config */
507 pbrms_clear_set_config(pbrms
);
509 pbrms
->nhgrp_name
= XSTRDUP(MTYPE_TMP
, name
);
510 pbr_map_check(pbrms
, true);
515 DEFPY(no_pbr_map_nexthop_group
, no_pbr_map_nexthop_group_cmd
,
516 "no set nexthop-group [NHGNAME$name]",
518 "Set for the PBR-MAP\n"
519 "nexthop-group to use\n"
520 "The name of the nexthop-group\n")
522 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
524 pbrms_clear_set_config(pbrms
);
529 DEFPY(pbr_map_nexthop
, pbr_map_nexthop_cmd
,
532 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
535 [nexthop-vrf NAME$vrf_name]",
536 "Set for the PBR-MAP\n"
537 "Specify one of the nexthops in this map\n"
542 "If the nexthop is in a different vrf tell us\n"
543 "The nexthop-vrf Name\n")
545 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
548 struct nexthop
*nh
= NULL
;
551 vrf
= vrf_lookup_by_name(vrf_name
);
553 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
556 vty_out(vty
, "Specified VRF: %s is non-existent\n", vrf_name
);
557 return CMD_WARNING_CONFIG_FAILED
;
560 memset(&nhop
, 0, sizeof(nhop
));
561 nhop
.vrf_id
= vrf
->vrf_id
;
564 struct interface
*ifp
= NULL
;
565 struct interface
*ifptmp
;
569 if (vrf_is_backend_netns() && vrf_name
) {
570 ifp
= if_lookup_by_name_vrf(intf
, vrf
);
572 RB_FOREACH (vrftmp
, vrf_name_head
, &vrfs_by_name
) {
573 ifptmp
= if_lookup_by_name_vrf(intf
, vrftmp
);
577 if (!vrf_is_backend_netns())
584 vty_out(vty
, "Specified Intf %s does not exist\n",
586 return CMD_WARNING_CONFIG_FAILED
;
590 "Specified Intf %s exists in multiple VRFs\n",
592 vty_out(vty
, "You must specify the nexthop-vrf\n");
593 return CMD_WARNING_CONFIG_FAILED
;
595 if (ifp
->vrf_id
!= vrf
->vrf_id
) {
598 actual
= vrf_lookup_by_id(ifp
->vrf_id
);
600 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
601 ifp
->name
, vrf
->name
, VRF_LOGNAME(actual
));
603 nhop
.ifindex
= ifp
->ifindex
;
604 nhop
.vrf_id
= ifp
->vrf_id
;
608 if (addr
->sa
.sa_family
== AF_INET
) {
609 nhop
.gate
.ipv4
.s_addr
= addr
->sin
.sin_addr
.s_addr
;
611 nhop
.type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
613 nhop
.type
= NEXTHOP_TYPE_IPV4
;
615 nhop
.gate
.ipv6
= addr
->sin6
.sin6_addr
;
617 nhop
.type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
619 if (IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
)) {
621 "Specified a v6 LL with no interface, rejecting\n");
622 return CMD_WARNING_CONFIG_FAILED
;
624 nhop
.type
= NEXTHOP_TYPE_IPV6
;
628 nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
631 nh
= nexthop_exists(pbrms
->nhg
, &nhop
);
633 if (nh
) /* Same config re-entered */
636 /* This is new/replacement config */
637 pbrms_clear_set_config(pbrms
);
639 pbr_nht_add_individual_nexthop(pbrms
, &nhop
);
641 pbr_map_check(pbrms
, true);
644 if (nhop
.type
== NEXTHOP_TYPE_IFINDEX
645 || (nhop
.type
== NEXTHOP_TYPE_IPV6_IFINDEX
646 && IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
))) {
647 struct interface
*ifp
;
649 ifp
= if_lookup_by_index(nhop
.ifindex
, nhop
.vrf_id
);
651 pbr_nht_nexthop_interface_update(ifp
);
657 DEFPY(no_pbr_map_nexthop
, no_pbr_map_nexthop_cmd
,
660 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
663 [nexthop-vrf NAME$vrf_name]]",
665 "Set for the PBR-MAP\n"
666 "Specify one of the nexthops in this map\n"
671 "If the nexthop is in a different vrf tell us\n"
672 "The nexthop-vrf Name\n")
674 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
676 pbrms_clear_set_config(pbrms
);
681 DEFPY(pbr_map_vrf
, pbr_map_vrf_cmd
,
682 "set vrf <NAME$vrf_name|unchanged>",
683 "Set for the PBR-MAP\n"
684 "Specify the VRF for this map\n"
686 "Use the interface's VRF for lookup\n")
688 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
691 * If an equivalent set vrf * exists, just return success.
693 if (vrf_name
&& pbrms
->vrf_lookup
694 && strncmp(pbrms
->vrf_name
, vrf_name
, sizeof(pbrms
->vrf_name
)) == 0)
696 else if (!vrf_name
&& pbrms
->vrf_unchanged
) /* Unchanged already set */
699 if (vrf_name
&& !pbr_vrf_lookup_by_name(vrf_name
)) {
700 vty_out(vty
, "Specified: %s is non-existent\n", vrf_name
);
701 return CMD_WARNING_CONFIG_FAILED
;
704 /* This is new/replacement config */
705 pbrms_clear_set_config(pbrms
);
708 pbrms
->vrf_lookup
= true;
709 strlcpy(pbrms
->vrf_name
, vrf_name
, sizeof(pbrms
->vrf_name
));
711 pbrms
->vrf_unchanged
= true;
713 pbr_map_check(pbrms
, true);
718 DEFPY(no_pbr_map_vrf
, no_pbr_map_vrf_cmd
,
719 "no set vrf [<NAME$vrf_name|unchanged>]",
721 "Set for the PBR-MAP\n"
722 "Specify the VRF for this map\n"
724 "Use the interface's VRF for lookup\n")
726 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
728 pbrms_clear_set_config(pbrms
);
735 "[no] pbr-policy PBRMAP$mapname",
738 "Name of the pbr-map to apply\n")
740 VTY_DECLVAR_CONTEXT(interface
, ifp
);
741 struct pbr_map
*pbrm
, *old_pbrm
;
742 struct pbr_interface
*pbr_ifp
= ifp
->info
;
745 pbrm
= pbrm_find(mapname
);
748 /* we don't want one and we don't have one, so... */
752 /* Some one could have fat fingered the interface name */
753 pbr_ifp
= pbr_if_new(ifp
);
757 if (strcmp(pbr_ifp
->mapname
, mapname
) == 0) {
758 pbr_ifp
->mapname
[0] = '\0';
760 pbr_map_interface_delete(pbrm
, ifp
);
763 if (strcmp(pbr_ifp
->mapname
, "") != 0) {
764 old_pbrm
= pbrm_find(pbr_ifp
->mapname
);
767 * So if we have an old pbrm we should only
768 * delete it if we are actually deleting and
769 * moving to a new pbrm
771 if (old_pbrm
&& old_pbrm
!= pbrm
)
772 pbr_map_interface_delete(old_pbrm
, ifp
);
774 snprintf(pbr_ifp
->mapname
, sizeof(pbr_ifp
->mapname
),
778 * So only reinstall if the old_pbrm and this pbrm are
781 if (pbrm
&& pbrm
!= old_pbrm
)
782 pbr_map_add_interface(pbrm
, ifp
);
794 pbr_nht_write_table_range(vty
);
795 pbr_nht_write_rule_range(vty
);
801 pbrms_nexthop_group_write_individual_nexthop(
802 struct vty
*vty
, const struct pbr_map_sequence
*pbrms
)
804 struct pbr_nexthop_group_cache find
;
805 struct pbr_nexthop_group_cache
*pnhgc
;
806 struct pbr_nexthop_cache lookup
;
807 struct pbr_nexthop_cache
*pnhc
;
809 memset(&find
, 0, sizeof(find
));
810 strlcpy(find
.name
, pbrms
->internal_nhg_name
, sizeof(find
.name
));
812 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
815 lookup
.nexthop
= *pbrms
->nhg
->nexthop
;
816 pnhc
= hash_lookup(pnhgc
->nhh
, &lookup
);
818 nexthop_group_write_nexthop_simple(
819 vty
, pbrms
->nhg
->nexthop
,
820 pnhc
->nexthop
.ifindex
!= 0 ? pnhc
->intf_name
: NULL
);
821 if (pnhc
->nexthop
.vrf_id
!= VRF_DEFAULT
)
822 vty_out(vty
, " nexthop-vrf %s", pnhc
->vrf_name
);
827 static void vty_show_pbrms(struct vty
*vty
,
828 const struct pbr_map_sequence
*pbrms
, bool detail
)
833 pbr_map_reason_string(pbrms
->reason
, rbuf
, sizeof(rbuf
));
835 vty_out(vty
, " Seq: %u rule: %u\n", pbrms
->seqno
, pbrms
->ruleno
);
838 vty_out(vty
, " Installed: %" PRIu64
"(%u) Reason: %s\n",
839 pbrms
->installed
, pbrms
->unique
,
840 pbrms
->reason
? rbuf
: "Valid");
842 vty_out(vty
, " Installed: %s Reason: %s\n",
843 pbrms
->installed
? "yes" : "no",
844 pbrms
->reason
? rbuf
: "Valid");
846 if (pbrms
->ip_proto
) {
849 p
= getprotobynumber(pbrms
->ip_proto
);
850 vty_out(vty
, " IP Protocol Match: %s\n", p
->p_name
);
854 vty_out(vty
, " SRC Match: %pFX\n", pbrms
->src
);
856 vty_out(vty
, " DST Match: %pFX\n", pbrms
->dst
);
857 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
858 vty_out(vty
, " DSCP Match: %u\n",
859 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
860 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
861 vty_out(vty
, " ECN Match: %u\n",
862 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
864 vty_out(vty
, " MARK Match: %u\n", pbrms
->mark
);
866 if (pbrms
->action_queue_id
!= PBR_MAP_UNDEFINED_QUEUE_ID
)
867 vty_out(vty
, " Set Queue ID %u\n",
868 pbrms
->action_queue_id
);
870 if (pbrms
->action_vlan_id
!= 0)
871 vty_out(vty
, " Set VLAN ID %u\n", pbrms
->action_vlan_id
);
872 if (pbrms
->action_vlan_flags
== PBR_MAP_STRIP_INNER_ANY
)
873 vty_out(vty
, " Strip VLAN ID\n");
874 if (pbrms
->action_pcp
)
875 vty_out(vty
, " Set PCP %u\n", pbrms
->action_pcp
);
878 if (pbrms
->nhgrp_name
) {
879 vty_out(vty
, " Nexthop-Group: %s\n", pbrms
->nhgrp_name
);
883 " Installed: %u(%d) Tableid: %d\n",
884 pbrms
->nhs_installed
,
885 pbr_nht_get_installed(pbrms
->nhgrp_name
),
886 pbr_nht_get_table(pbrms
->nhgrp_name
));
888 vty_out(vty
, " Installed: %s Tableid: %d\n",
889 pbr_nht_get_installed(pbrms
->nhgrp_name
) ? "yes"
891 pbr_nht_get_table(pbrms
->nhgrp_name
));
893 } else if (pbrms
->nhg
) {
895 pbrms_nexthop_group_write_individual_nexthop(vty
, pbrms
);
898 " Installed: %u(%d) Tableid: %d\n",
899 pbrms
->nhs_installed
,
900 pbr_nht_get_installed(pbrms
->internal_nhg_name
),
901 pbr_nht_get_table(pbrms
->internal_nhg_name
));
903 vty_out(vty
, " Installed: %s Tableid: %d\n",
904 pbr_nht_get_installed(pbrms
->internal_nhg_name
)
907 pbr_nht_get_table(pbrms
->internal_nhg_name
));
909 } else if (pbrms
->vrf_unchanged
) {
910 vty_out(vty
, " VRF Unchanged (use interface vrf)\n");
911 } else if (pbrms
->vrf_lookup
) {
912 vty_out(vty
, " VRF Lookup: %s\n", pbrms
->vrf_name
);
914 vty_out(vty
, " Nexthop-Group: Unknown Installed: no\n");
918 static void vty_json_pbrms(json_object
*j
, struct vty
*vty
,
919 const struct pbr_map_sequence
*pbrms
)
921 json_object
*jpbrm
, *nexthop_group
;
922 char *nhg_name
= pbrms
->nhgrp_name
? pbrms
->nhgrp_name
923 : pbrms
->internal_nhg_name
;
924 char buf
[PREFIX_STRLEN
];
927 jpbrm
= json_object_new_object();
929 json_object_int_add(jpbrm
, "id", pbrms
->unique
);
932 pbr_map_reason_string(pbrms
->reason
, rbuf
, sizeof(rbuf
));
934 json_object_int_add(jpbrm
, "sequenceNumber", pbrms
->seqno
);
935 json_object_int_add(jpbrm
, "ruleNumber", pbrms
->ruleno
);
936 json_object_boolean_add(jpbrm
, "vrfUnchanged", pbrms
->vrf_unchanged
);
937 json_object_boolean_add(jpbrm
, "installed",
938 pbr_nht_get_installed(nhg_name
));
939 json_object_string_add(jpbrm
, "installedReason",
940 pbrms
->reason
? rbuf
: "Valid");
943 nexthop_group
= json_object_new_object();
945 json_object_int_add(nexthop_group
, "tableId",
946 pbr_nht_get_table(nhg_name
));
947 json_object_string_add(nexthop_group
, "name", nhg_name
);
948 json_object_boolean_add(nexthop_group
, "installed",
949 pbr_nht_get_installed(nhg_name
));
950 json_object_int_add(nexthop_group
, "installedInternally",
951 pbrms
->nhs_installed
);
953 json_object_object_add(jpbrm
, "nexthopGroup", nexthop_group
);
956 if (pbrms
->vrf_lookup
)
957 json_object_string_add(jpbrm
, "vrfName", pbrms
->vrf_name
);
960 json_object_string_add(
962 prefix2str(pbrms
->src
, buf
, sizeof(buf
)));
964 json_object_string_add(
966 prefix2str(pbrms
->dst
, buf
, sizeof(buf
)));
968 json_object_int_add(jpbrm
, "matchMark", pbrms
->mark
);
969 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
970 json_object_int_add(jpbrm
, "matchDscp",
971 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
972 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
973 json_object_int_add(jpbrm
, "matchEcn",
974 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
976 json_object_array_add(j
, jpbrm
);
979 static void vty_show_pbr_map(struct vty
*vty
, const struct pbr_map
*pbrm
,
982 struct pbr_map_sequence
*pbrms
;
983 struct listnode
*node
;
985 vty_out(vty
, " pbr-map %s valid: %s\n", pbrm
->name
,
986 pbrm
->valid
? "yes" : "no");
988 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
989 vty_show_pbrms(vty
, pbrms
, detail
);
992 static void vty_json_pbr_map(json_object
*j
, struct vty
*vty
,
993 const struct pbr_map
*pbrm
)
995 struct pbr_map_sequence
*pbrms
;
996 struct listnode
*node
;
999 json_object_string_add(j
, "name", pbrm
->name
);
1000 json_object_boolean_add(j
, "valid", pbrm
->valid
);
1002 jpbrms
= json_object_new_array();
1004 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
1005 vty_json_pbrms(jpbrms
, vty
, pbrms
);
1007 json_object_object_add(j
, "policies", jpbrms
);
1010 DEFPY (show_pbr_map
,
1012 "show pbr map [NAME$name] [detail$detail|json$json]",
1017 "Detailed information\n"
1020 struct pbr_map
*pbrm
;
1021 json_object
*j
= NULL
;
1024 j
= json_object_new_array();
1026 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
1027 json_object
*this_map
= NULL
;
1028 if (name
&& strcmp(name
, pbrm
->name
) != 0)
1032 this_map
= json_object_new_object();
1035 vty_json_pbr_map(this_map
, vty
, pbrm
);
1037 json_object_array_add(j
, this_map
);
1041 vty_show_pbr_map(vty
, pbrm
, detail
);
1045 vty_out(vty
, "%s\n",
1046 json_object_to_json_string_ext(
1047 j
, JSON_C_TO_STRING_PRETTY
));
1048 json_object_free(j
);
1054 DEFPY(show_pbr_nexthop_group
,
1055 show_pbr_nexthop_group_cmd
,
1056 "show pbr nexthop-groups [WORD$word] [json$json]",
1060 "Optional Name of the nexthop group\n"
1063 json_object
*j
= NULL
;
1066 j
= json_object_new_array();
1069 pbr_nht_json_nexthop_group(j
, word
);
1071 vty_out(vty
, "%s\n",
1072 json_object_to_json_string_ext(
1073 j
, JSON_C_TO_STRING_PRETTY
));
1075 json_object_free(j
);
1077 pbr_nht_show_nexthop_group(vty
, word
);
1083 DEFPY (show_pbr_interface
,
1084 show_pbr_interface_cmd
,
1085 "show pbr interface [NAME$name] [json$json]",
1089 "PBR Interface Name\n"
1092 struct interface
*ifp
;
1094 struct pbr_interface
*pbr_ifp
;
1095 json_object
*j
= NULL
;
1098 j
= json_object_new_array();
1100 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1101 FOR_ALL_INTERFACES(vrf
, ifp
) {
1102 struct pbr_map
*pbrm
;
1103 json_object
*this_iface
= NULL
;
1106 this_iface
= json_object_new_object();
1109 json_object_free(this_iface
);
1113 if (name
&& strcmp(ifp
->name
, name
) != 0) {
1114 json_object_free(this_iface
);
1118 pbr_ifp
= ifp
->info
;
1120 if (strcmp(pbr_ifp
->mapname
, "") == 0) {
1121 json_object_free(this_iface
);
1125 pbrm
= pbrm_find(pbr_ifp
->mapname
);
1128 json_object_string_add(this_iface
, "name",
1130 json_object_int_add(this_iface
, "index",
1132 json_object_string_add(this_iface
, "policy",
1134 json_object_boolean_add(this_iface
, "valid",
1137 json_object_array_add(j
, this_iface
);
1141 vty_out(vty
, " %s(%d) with pbr-policy %s", ifp
->name
,
1142 ifp
->ifindex
, pbr_ifp
->mapname
);
1144 vty_out(vty
, " (map doesn't exist)");
1150 vty_out(vty
, "%s\n",
1151 json_object_to_json_string_ext(
1152 j
, JSON_C_TO_STRING_PRETTY
));
1153 json_object_free(j
);
1159 /* PBR debugging CLI ------------------------------------------------------- */
1161 static struct cmd_node debug_node
= {
1165 .config_write
= pbr_debug_config_write
,
1170 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
1175 "PBRD <-> Zebra communications\n"
1176 "Nexthop tracking\n"
1179 uint32_t mode
= DEBUG_NODE2MODE(vty
->node
);
1182 DEBUG_MODE_SET(&pbr_dbg_map
, mode
, !no
);
1184 DEBUG_MODE_SET(&pbr_dbg_zebra
, mode
, !no
);
1186 DEBUG_MODE_SET(&pbr_dbg_nht
, mode
, !no
);
1188 DEBUG_MODE_SET(&pbr_dbg_event
, mode
, !no
);
1190 /* no specific debug --> act on all of them */
1191 if (strmatch(argv
[argc
- 1]->text
, "pbr"))
1192 pbr_debug_set_all(mode
, !no
);
1197 DEFUN_NOSH(show_debugging_pbr
,
1198 show_debugging_pbr_cmd
,
1199 "show debugging [pbr]",
1204 vty_out(vty
, "PBR debugging status:\n");
1206 pbr_debug_config_write_helper(vty
, false);
1211 /* ------------------------------------------------------------------------- */
1214 static int pbr_interface_config_write(struct vty
*vty
)
1216 struct interface
*ifp
;
1219 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1220 FOR_ALL_INTERFACES (vrf
, ifp
) {
1221 if (vrf
->vrf_id
== VRF_DEFAULT
)
1222 vty_frame(vty
, "interface %s\n", ifp
->name
);
1224 vty_frame(vty
, "interface %s vrf %s\n",
1225 ifp
->name
, vrf
->name
);
1228 vty_out(vty
, " description %s\n", ifp
->desc
);
1230 pbr_map_write_interfaces(vty
, ifp
);
1232 vty_endframe(vty
, "exit\n!\n");
1239 static int pbr_vty_map_config_write(struct vty
*vty
);
1240 /* PBR map node structure. */
1241 static struct cmd_node pbr_map_node
= {
1243 .node
= PBRMAP_NODE
,
1244 .parent_node
= CONFIG_NODE
,
1245 .prompt
= "%s(config-pbr-map)# ",
1246 .config_write
= pbr_vty_map_config_write
,
1249 static int pbr_vty_map_config_write_sequence(struct vty
*vty
,
1250 struct pbr_map
*pbrm
,
1251 struct pbr_map_sequence
*pbrms
)
1253 vty_out(vty
, "pbr-map %s seq %u\n", pbrm
->name
, pbrms
->seqno
);
1256 vty_out(vty
, " match src-ip %pFX\n", pbrms
->src
);
1259 vty_out(vty
, " match dst-ip %pFX\n", pbrms
->dst
);
1262 vty_out(vty
, " match src-port %u\n", pbrms
->src_prt
);
1264 vty_out(vty
, " match dst-port %u\n", pbrms
->dst_prt
);
1266 if (pbrms
->ip_proto
) {
1269 p
= getprotobynumber(pbrms
->ip_proto
);
1270 vty_out(vty
, " match ip-protocol %s\n", p
->p_name
);
1273 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
1274 vty_out(vty
, " match dscp %u\n",
1275 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
1277 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
1278 vty_out(vty
, " match ecn %u\n",
1279 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
1282 vty_out(vty
, " match mark %u\n", pbrms
->mark
);
1285 if (pbrms
->action_queue_id
!= PBR_MAP_UNDEFINED_QUEUE_ID
)
1286 vty_out(vty
, " set queue-id %d\n", pbrms
->action_queue_id
);
1288 if (pbrms
->action_pcp
)
1289 vty_out(vty
, " set pcp %d\n", pbrms
->action_pcp
);
1291 if (pbrms
->action_vlan_id
)
1292 vty_out(vty
, " set vlan %u\n", pbrms
->action_vlan_id
);
1294 if (pbrms
->action_vlan_flags
== PBR_MAP_STRIP_INNER_ANY
)
1295 vty_out(vty
, " strip vlan any\n");
1297 if (pbrms
->vrf_unchanged
)
1298 vty_out(vty
, " set vrf unchanged\n");
1300 if (pbrms
->vrf_lookup
)
1301 vty_out(vty
, " set vrf %s\n", pbrms
->vrf_name
);
1303 if (pbrms
->nhgrp_name
)
1304 vty_out(vty
, " set nexthop-group %s\n", pbrms
->nhgrp_name
);
1307 vty_out(vty
, " set ");
1308 pbrms_nexthop_group_write_individual_nexthop(vty
, pbrms
);
1311 vty_out(vty
, "exit\n");
1312 vty_out(vty
, "!\n");
1316 static int pbr_vty_map_config_write(struct vty
*vty
)
1318 struct pbr_map
*pbrm
;
1320 pbr_nht_write_table_range(vty
);
1321 pbr_nht_write_rule_range(vty
);
1323 RB_FOREACH(pbrm
, pbr_map_entry_head
, &pbr_maps
) {
1324 struct pbr_map_sequence
*pbrms
;
1325 struct listnode
*node
;
1327 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
1328 pbr_vty_map_config_write_sequence(vty
, pbrm
, pbrms
);
1334 static void pbr_map_completer(vector comps
, struct cmd_token
*token
)
1336 struct pbr_map
*pbrm
;
1338 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
)
1339 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, pbrm
->name
));
1342 static const struct cmd_variable_handler pbr_map_name
[] = {
1344 .tokenname
= "PBRMAP", .completions
= pbr_map_completer
,
1351 extern struct zebra_privs_t pbr_privs
;
1353 void pbr_vty_init(void)
1355 cmd_variable_handler_register(pbr_map_name
);
1359 if_cmd_init(pbr_interface_config_write
);
1361 install_node(&pbr_map_node
);
1364 install_node(&debug_node
);
1365 install_element(ENABLE_NODE
, &debug_pbr_cmd
);
1366 install_element(CONFIG_NODE
, &debug_pbr_cmd
);
1367 install_element(ENABLE_NODE
, &show_debugging_pbr_cmd
);
1369 install_default(PBRMAP_NODE
);
1371 install_element(CONFIG_NODE
, &pbr_map_cmd
);
1372 install_element(CONFIG_NODE
, &no_pbr_map_cmd
);
1373 install_element(CONFIG_NODE
, &pbr_set_table_range_cmd
);
1374 install_element(CONFIG_NODE
, &no_pbr_set_table_range_cmd
);
1375 install_element(INTERFACE_NODE
, &pbr_policy_cmd
);
1376 install_element(PBRMAP_NODE
, &pbr_map_match_ip_proto_cmd
);
1377 install_element(PBRMAP_NODE
, &pbr_map_match_src_port_cmd
);
1378 install_element(PBRMAP_NODE
, &pbr_map_match_dst_port_cmd
);
1379 install_element(PBRMAP_NODE
, &pbr_map_match_src_cmd
);
1380 install_element(PBRMAP_NODE
, &pbr_map_match_dst_cmd
);
1381 install_element(PBRMAP_NODE
, &pbr_map_match_dscp_cmd
);
1382 install_element(PBRMAP_NODE
, &pbr_map_match_ecn_cmd
);
1383 install_element(PBRMAP_NODE
, &pbr_map_match_mark_cmd
);
1384 install_element(PBRMAP_NODE
, &pbr_map_action_queue_id_cmd
);
1385 install_element(PBRMAP_NODE
, &pbr_map_action_strip_vlan_cmd
);
1386 install_element(PBRMAP_NODE
, &pbr_map_action_vlan_id_cmd
);
1387 install_element(PBRMAP_NODE
, &pbr_map_action_pcp_cmd
);
1388 install_element(PBRMAP_NODE
, &pbr_map_nexthop_group_cmd
);
1389 install_element(PBRMAP_NODE
, &no_pbr_map_nexthop_group_cmd
);
1390 install_element(PBRMAP_NODE
, &pbr_map_nexthop_cmd
);
1391 install_element(PBRMAP_NODE
, &no_pbr_map_nexthop_cmd
);
1392 install_element(PBRMAP_NODE
, &pbr_map_vrf_cmd
);
1393 install_element(PBRMAP_NODE
, &no_pbr_map_vrf_cmd
);
1394 install_element(VIEW_NODE
, &show_pbr_cmd
);
1395 install_element(VIEW_NODE
, &show_pbr_map_cmd
);
1396 install_element(VIEW_NODE
, &show_pbr_interface_cmd
);
1397 install_element(VIEW_NODE
, &show_pbr_nexthop_group_cmd
);