1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2018 Cumulus Networks, Inc.
14 #include "nexthop_group.h"
15 #include "nexthop_group_private.h"
21 #include "pbrd/pbr_nht.h"
22 #include "pbrd/pbr_map.h"
23 #include "pbrd/pbr_zebra.h"
24 #include "pbrd/pbr_vty.h"
25 #include "pbrd/pbr_debug.h"
26 #include "pbrd/pbr_vty_clippy.c"
28 DEFUN_NOSH(pbr_map
, pbr_map_cmd
, "pbr-map PBRMAP seq (1-700)",
29 "Create pbr-map or enter pbr-map command mode\n"
30 "The name of the PBR MAP\n"
31 "Sequence to insert in existing pbr-map entry\n"
34 const char *pbrm_name
= argv
[1]->arg
;
35 uint32_t seqno
= atoi(argv
[3]->arg
);
36 struct pbr_map_sequence
*pbrms
;
38 pbrms
= pbrms_get(pbrm_name
, seqno
);
39 VTY_PUSH_CONTEXT(PBRMAP_NODE
, pbrms
);
44 DEFUN_NOSH(no_pbr_map
, no_pbr_map_cmd
, "no pbr-map PBRMAP [seq (1-700)]",
47 "The name of the PBR MAP\n"
48 "Sequence to delete from existing pbr-map entry\n"
51 const char *pbrm_name
= argv
[2]->arg
;
53 struct pbr_map
*pbrm
= pbrm_find(pbrm_name
);
54 struct pbr_map_sequence
*pbrms
;
55 struct listnode
*node
, *next_node
;
58 seqno
= atoi(argv
[4]->arg
);
61 vty_out(vty
, "pbr-map %s not found\n", pbrm_name
);
65 for (ALL_LIST_ELEMENTS(pbrm
->seqnumbers
, node
, next_node
, pbrms
)) {
66 if (seqno
&& pbrms
->seqno
!= seqno
)
69 pbr_map_delete(pbrms
);
75 DEFPY(pbr_set_table_range
,
76 pbr_set_table_range_cmd
,
77 "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
79 "Set table ID range\n"
80 "Set table ID range\n"
81 "Lower bound for table ID range\n"
82 "Upper bound for table ID range\n")
84 /* upper bound is 2^32 - 2^10 */
85 int ret
= CMD_WARNING
;
86 const int minrange
= 1000;
88 /* validate given bounds */
90 vty_out(vty
, "%% Lower bound must be less than upper bound\n");
91 else if (ub
- lb
< minrange
)
92 vty_out(vty
, "%% Range breadth must be at least %d\n", minrange
);
95 pbr_nht_set_tableid_range((uint32_t) lb
, (uint32_t) ub
);
101 DEFPY(no_pbr_set_table_range
, no_pbr_set_table_range_cmd
,
102 "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
105 "Set table ID range\n"
106 "Set table ID range\n"
107 "Lower bound for table ID range\n"
108 "Upper bound for table ID range\n")
110 pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID
,
111 PBR_NHT_DEFAULT_HIGH_TABLEID
);
115 DEFPY(pbr_map_match_src
, pbr_map_match_src_cmd
,
116 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
118 "Match the rest of the command\n"
119 "Choose the src ip or ipv6 prefix to use\n"
123 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
126 return CMD_WARNING_CONFIG_FAILED
;
128 if (pbrms
->dst
&& pbrms
->family
&& prefix
->family
!= pbrms
->family
) {
129 vty_out(vty
, "Cannot mismatch families within match src/dst\n");
130 return CMD_WARNING_CONFIG_FAILED
;
133 pbrms
->family
= prefix
->family
;
137 if (prefix_same(pbrms
->src
, prefix
))
140 pbrms
->src
= prefix_new();
142 prefix_copy(pbrms
->src
, prefix
);
144 prefix_free(&pbrms
->src
);
146 pbr_map_check(pbrms
, true);
151 DEFPY(pbr_map_match_dst
, pbr_map_match_dst_cmd
,
152 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
154 "Match the rest of the command\n"
155 "Choose the dst ip or ipv6 prefix to use\n"
159 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
162 return CMD_WARNING_CONFIG_FAILED
;
164 if (pbrms
->src
&& pbrms
->family
&& prefix
->family
!= pbrms
->family
) {
165 vty_out(vty
, "Cannot mismatch families within match src/dst\n");
166 return CMD_WARNING_CONFIG_FAILED
;
169 pbrms
->family
= prefix
->family
;
173 if (prefix_same(pbrms
->dst
, prefix
))
176 pbrms
->dst
= prefix_new();
178 prefix_copy(pbrms
->dst
, prefix
);
180 prefix_free(&pbrms
->dst
);
182 pbr_map_check(pbrms
, true);
187 DEFPY(pbr_map_match_ip_proto
, pbr_map_match_ip_proto_cmd
,
188 "[no] match ip-protocol [tcp|udp]$ip_proto",
190 "Match the rest of the command\n"
191 "Choose an ip-protocol\n"
192 "Match on tcp flows\n"
193 "Match on udp flows\n")
195 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
199 return CMD_WARNING_CONFIG_FAILED
;
202 p
= getprotobyname(ip_proto
);
204 vty_out(vty
, "Unable to convert %s to proto id\n",
209 pbrms
->ip_proto
= p
->p_proto
;
216 DEFPY(pbr_map_match_src_port
, pbr_map_match_src_port_cmd
,
217 "[no] match src-port (1-65535)$port",
219 "Match the rest of the command\n"
220 "Choose the source port to use\n"
223 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
226 return CMD_WARNING_CONFIG_FAILED
;
229 if (pbrms
->src_prt
== port
)
232 pbrms
->src_prt
= port
;
236 pbr_map_check(pbrms
, true);
241 DEFPY(pbr_map_match_dst_port
, pbr_map_match_dst_port_cmd
,
242 "[no] match dst-port (1-65535)$port",
244 "Match the rest of the command\n"
245 "Choose the destination port to use\n"
246 "The Destination Port\n")
248 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
251 return CMD_WARNING_CONFIG_FAILED
;
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
);
278 return CMD_WARNING_CONFIG_FAILED
;
280 /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
281 bool isANumber
= true;
282 for (int i
= 0; i
< (int)strlen(dscp
); i
++) {
283 /* Letters are not numbers */
284 if (!isdigit(dscp
[i
]))
287 /* Lowercase the dscp enum (if needed) */
288 if (isupper(dscp
[i
]))
289 dscpname
[i
] = tolower(dscp
[i
]);
291 dscpname
[i
] = dscp
[i
];
293 dscpname
[strlen(dscp
)] = '\0';
296 /* dscp passed is a regular number */
297 long dscpAsNum
= strtol(dscp
, NULL
, 0);
299 if (dscpAsNum
> PBR_DSFIELD_DSCP
>> 2) {
300 /* Refuse to install on overflow */
301 vty_out(vty
, "dscp (%s) must be less than 64\n", dscp
);
302 return CMD_WARNING_CONFIG_FAILED
;
306 /* check dscp if it is an enum like cs0 */
307 rawDscp
= pbr_map_decode_dscp_enum(dscpname
);
308 if (rawDscp
> PBR_DSFIELD_DSCP
) {
309 vty_out(vty
, "Invalid dscp value: %s\n", dscpname
);
310 return CMD_WARNING_CONFIG_FAILED
;
315 if (((pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2) == rawDscp
)
318 /* Set the DSCP bits of the DSField */
320 (pbrms
->dsfield
& ~PBR_DSFIELD_DSCP
) | (rawDscp
<< 2);
322 pbrms
->dsfield
&= ~PBR_DSFIELD_DSCP
;
325 pbr_map_check(pbrms
, true);
330 DEFPY(pbr_map_match_ecn
, pbr_map_match_ecn_cmd
,
331 "[no] match ecn (0-3)$ecn",
333 "Match the rest of the command\n"
334 "Match based on IP ECN field\n"
335 "Explicit Congestion Notification\n")
337 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
340 return CMD_WARNING_CONFIG_FAILED
;
343 if ((pbrms
->dsfield
& PBR_DSFIELD_ECN
) == ecn
)
346 /* Set the ECN bits of the DSField */
347 pbrms
->dsfield
= (pbrms
->dsfield
& ~PBR_DSFIELD_ECN
) | ecn
;
349 pbrms
->dsfield
&= ~PBR_DSFIELD_ECN
;
352 pbr_map_check(pbrms
, true);
357 DEFPY(pbr_map_match_mark
, pbr_map_match_mark_cmd
,
358 "[no] match mark (1-4294967295)$mark",
360 "Match the rest of the command\n"
361 "Choose the mark value to use\n"
364 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
367 return CMD_WARNING_CONFIG_FAILED
;
370 vty_out(vty
, "pbr marks are not supported on this platform\n");
371 return CMD_WARNING_CONFIG_FAILED
;
376 if (pbrms
->mark
== (uint32_t)mark
)
379 pbrms
->mark
= (uint32_t)mark
;
383 pbr_map_check(pbrms
, true);
388 static void pbrms_clear_set_vrf_config(struct pbr_map_sequence
*pbrms
)
390 if (pbrms
->vrf_lookup
|| pbrms
->vrf_unchanged
) {
391 pbr_map_delete_vrf(pbrms
);
392 pbrms
->vrf_name
[0] = '\0';
393 pbrms
->vrf_lookup
= false;
394 pbrms
->vrf_unchanged
= false;
398 static void pbrms_clear_set_nhg_config(struct pbr_map_sequence
*pbrms
)
400 if (pbrms
->nhgrp_name
)
401 pbr_map_delete_nexthops(pbrms
);
404 static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence
*pbrms
)
407 pbr_nht_delete_individual_nexthop(pbrms
);
410 static void pbrms_clear_set_config(struct pbr_map_sequence
*pbrms
)
412 pbrms_clear_set_vrf_config(pbrms
);
413 pbrms_clear_set_nhg_config(pbrms
);
414 pbrms_clear_set_nexthop_config(pbrms
);
416 pbrms
->nhs_installed
= false;
420 DEFPY(pbr_map_action_queue_id
, pbr_map_action_queue_id_cmd
,
421 "[no] set queue-id <(1-65535)$queue_id>",
423 "Set the rest of the command\n"
424 "Set based on egress port queue id\n"
425 "A valid value in range 1..65535 \n")
427 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
430 return CMD_WARNING_CONFIG_FAILED
;
433 pbrms
->action_queue_id
= queue_id
;
434 else if ((uint32_t)queue_id
== pbrms
->action_queue_id
)
435 pbrms
->action_queue_id
= PBR_MAP_UNDEFINED_QUEUE_ID
;
437 pbr_map_check(pbrms
, true);
442 DEFPY(pbr_map_action_pcp
, pbr_map_action_pcp_cmd
, "[no] set pcp <(0-7)$pcp>",
444 "Set the rest of the command\n"
445 "Set based on 802.1p Priority Code Point (PCP) value\n"
446 "A valid value in range 0..7\n")
448 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
451 return CMD_WARNING_CONFIG_FAILED
;
454 pbrms
->action_pcp
= pcp
;
455 else if (pcp
== pbrms
->action_pcp
)
456 pbrms
->action_pcp
= 0;
458 pbr_map_check(pbrms
, true);
463 DEFPY(pbr_map_action_vlan_id
, pbr_map_action_vlan_id_cmd
,
464 "[no] set vlan <(1-4094)$vlan_id>",
466 "Set the rest of the command\n"
467 "Set action for VLAN tagging\n"
468 "A valid value in range 1..4094\n")
470 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
473 return CMD_WARNING_CONFIG_FAILED
;
476 pbrms
->action_vlan_id
= vlan_id
;
477 else if (pbrms
->action_vlan_id
== vlan_id
)
478 pbrms
->action_vlan_id
= 0;
480 pbr_map_check(pbrms
, true);
485 DEFPY(pbr_map_action_strip_vlan
, pbr_map_action_strip_vlan_cmd
,
488 "Strip the vlan tags from frame\n"
489 "Strip any inner vlan tag \n")
491 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
494 return CMD_WARNING_CONFIG_FAILED
;
497 pbrms
->action_vlan_flags
= PBR_MAP_STRIP_INNER_ANY
;
499 pbrms
->action_vlan_flags
= 0;
501 pbr_map_check(pbrms
, true);
507 DEFPY(pbr_map_nexthop_group
, pbr_map_nexthop_group_cmd
,
508 "set nexthop-group NHGNAME$name",
509 "Set for the PBR-MAP\n"
510 "nexthop-group to use\n"
511 "The name of the nexthop-group\n")
513 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
514 struct nexthop_group_cmd
*nhgc
;
517 return CMD_WARNING_CONFIG_FAILED
;
519 nhgc
= nhgc_find(name
);
521 vty_out(vty
, "Specified nexthop-group %s does not exist\n",
524 "PBR-MAP will not be applied until it is created\n");
527 if (pbrms
->nhgrp_name
&& strcmp(name
, pbrms
->nhgrp_name
) == 0)
530 /* This is new/replacement config */
531 pbrms_clear_set_config(pbrms
);
533 pbr_nht_set_seq_nhg(pbrms
, name
);
535 pbr_map_check(pbrms
, true);
540 DEFPY(no_pbr_map_nexthop_group
, no_pbr_map_nexthop_group_cmd
,
541 "no set nexthop-group [NHGNAME$name]",
543 "Set for the PBR-MAP\n"
544 "nexthop-group to use\n"
545 "The name of the nexthop-group\n")
547 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
550 return CMD_WARNING_CONFIG_FAILED
;
552 pbrms_clear_set_config(pbrms
);
557 DEFPY(pbr_map_nexthop
, pbr_map_nexthop_cmd
,
560 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
563 [nexthop-vrf NAME$vrf_name]",
564 "Set for the PBR-MAP\n"
565 "Specify one of the nexthops in this map\n"
570 "If the nexthop is in a different vrf tell us\n"
571 "The nexthop-vrf Name\n")
573 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
576 struct nexthop
*nh
= NULL
;
579 return CMD_WARNING_CONFIG_FAILED
;
582 vrf
= vrf_lookup_by_name(vrf_name
);
584 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
587 vty_out(vty
, "Specified VRF: %s is non-existent\n", vrf_name
);
588 return CMD_WARNING_CONFIG_FAILED
;
591 memset(&nhop
, 0, sizeof(nhop
));
592 nhop
.vrf_id
= vrf
->vrf_id
;
595 struct interface
*ifp
= NULL
;
596 struct interface
*ifptmp
;
600 if (vrf_is_backend_netns() && vrf_name
) {
601 ifp
= if_lookup_by_name_vrf(intf
, vrf
);
603 RB_FOREACH (vrftmp
, vrf_name_head
, &vrfs_by_name
) {
604 ifptmp
= if_lookup_by_name_vrf(intf
, vrftmp
);
608 if (!vrf_is_backend_netns())
615 vty_out(vty
, "Specified Intf %s does not exist\n",
617 return CMD_WARNING_CONFIG_FAILED
;
621 "Specified Intf %s exists in multiple VRFs\n",
623 vty_out(vty
, "You must specify the nexthop-vrf\n");
624 return CMD_WARNING_CONFIG_FAILED
;
626 if (ifp
->vrf
->vrf_id
!= vrf
->vrf_id
)
628 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
629 ifp
->name
, vrf
->name
, ifp
->vrf
->name
);
630 nhop
.ifindex
= ifp
->ifindex
;
631 nhop
.vrf_id
= ifp
->vrf
->vrf_id
;
635 if (addr
->sa
.sa_family
== AF_INET
) {
636 nhop
.gate
.ipv4
.s_addr
= addr
->sin
.sin_addr
.s_addr
;
638 nhop
.type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
640 nhop
.type
= NEXTHOP_TYPE_IPV4
;
642 nhop
.gate
.ipv6
= addr
->sin6
.sin6_addr
;
644 nhop
.type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
646 if (IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
)) {
648 "Specified a v6 LL with no interface, rejecting\n");
649 return CMD_WARNING_CONFIG_FAILED
;
651 nhop
.type
= NEXTHOP_TYPE_IPV6
;
655 nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
658 nh
= nexthop_exists(pbrms
->nhg
, &nhop
);
660 if (nh
) /* Same config re-entered */
663 /* This is new/replacement config */
664 pbrms_clear_set_config(pbrms
);
666 pbr_nht_add_individual_nexthop(pbrms
, &nhop
);
668 pbr_map_check(pbrms
, true);
671 if (nhop
.type
== NEXTHOP_TYPE_IFINDEX
672 || (nhop
.type
== NEXTHOP_TYPE_IPV6_IFINDEX
673 && IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
))) {
674 struct interface
*ifp
;
676 ifp
= if_lookup_by_index(nhop
.ifindex
, nhop
.vrf_id
);
678 pbr_nht_nexthop_interface_update(ifp
);
684 DEFPY(no_pbr_map_nexthop
, no_pbr_map_nexthop_cmd
,
687 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
690 [nexthop-vrf NAME$vrf_name]]",
692 "Set for the PBR-MAP\n"
693 "Specify one of the nexthops in this map\n"
698 "If the nexthop is in a different vrf tell us\n"
699 "The nexthop-vrf Name\n")
701 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
704 return CMD_WARNING_CONFIG_FAILED
;
706 pbrms_clear_set_config(pbrms
);
711 DEFPY(pbr_map_vrf
, pbr_map_vrf_cmd
,
712 "set vrf <NAME$vrf_name|unchanged>",
713 "Set for the PBR-MAP\n"
714 "Specify the VRF for this map\n"
716 "Use the interface's VRF for lookup\n")
718 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
721 return CMD_WARNING_CONFIG_FAILED
;
724 * If an equivalent set vrf * exists, just return success.
726 if (vrf_name
&& pbrms
->vrf_lookup
727 && strncmp(pbrms
->vrf_name
, vrf_name
, sizeof(pbrms
->vrf_name
)) == 0)
729 else if (!vrf_name
&& pbrms
->vrf_unchanged
) /* Unchanged already set */
732 if (vrf_name
&& !pbr_vrf_lookup_by_name(vrf_name
)) {
733 vty_out(vty
, "Specified: %s is non-existent\n", vrf_name
);
734 return CMD_WARNING_CONFIG_FAILED
;
737 /* This is new/replacement config */
738 pbrms_clear_set_config(pbrms
);
741 pbrms
->vrf_lookup
= true;
742 strlcpy(pbrms
->vrf_name
, vrf_name
, sizeof(pbrms
->vrf_name
));
744 pbrms
->vrf_unchanged
= true;
746 pbr_map_check(pbrms
, true);
751 DEFPY(no_pbr_map_vrf
, no_pbr_map_vrf_cmd
,
752 "no set vrf [<NAME$vrf_name|unchanged>]",
754 "Set for the PBR-MAP\n"
755 "Specify the VRF for this map\n"
757 "Use the interface's VRF for lookup\n")
759 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
762 return CMD_WARNING_CONFIG_FAILED
;
764 pbrms_clear_set_config(pbrms
);
771 "[no] pbr-policy PBRMAP$mapname",
774 "Name of the pbr-map to apply\n")
776 VTY_DECLVAR_CONTEXT(interface
, ifp
);
777 struct pbr_map
*pbrm
, *old_pbrm
;
778 struct pbr_interface
*pbr_ifp
= ifp
->info
;
781 pbrm
= pbrm_find(mapname
);
784 /* we don't want one and we don't have one, so... */
788 /* Some one could have fat fingered the interface name */
789 pbr_ifp
= pbr_if_new(ifp
);
793 if (strcmp(pbr_ifp
->mapname
, mapname
) == 0) {
794 pbr_ifp
->mapname
[0] = '\0';
796 pbr_map_interface_delete(pbrm
, ifp
);
799 if (strcmp(pbr_ifp
->mapname
, "") != 0) {
800 old_pbrm
= pbrm_find(pbr_ifp
->mapname
);
803 * So if we have an old pbrm we should only
804 * delete it if we are actually deleting and
805 * moving to a new pbrm
807 if (old_pbrm
&& old_pbrm
!= pbrm
)
808 pbr_map_interface_delete(old_pbrm
, ifp
);
810 snprintf(pbr_ifp
->mapname
, sizeof(pbr_ifp
->mapname
),
814 * So only reinstall if the old_pbrm and this pbrm are
817 if (pbrm
&& pbrm
!= old_pbrm
)
818 pbr_map_add_interface(pbrm
, ifp
);
830 pbr_nht_write_table_range(vty
);
831 pbr_nht_write_rule_range(vty
);
837 pbrms_nexthop_group_write_individual_nexthop(
838 struct vty
*vty
, const struct pbr_map_sequence
*pbrms
)
840 struct pbr_nexthop_group_cache find
;
841 struct pbr_nexthop_group_cache
*pnhgc
;
842 struct pbr_nexthop_cache lookup
;
843 struct pbr_nexthop_cache
*pnhc
;
845 memset(&find
, 0, sizeof(find
));
846 strlcpy(find
.name
, pbrms
->internal_nhg_name
, sizeof(find
.name
));
848 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
851 lookup
.nexthop
= *pbrms
->nhg
->nexthop
;
852 pnhc
= hash_lookup(pnhgc
->nhh
, &lookup
);
854 nexthop_group_write_nexthop_simple(
855 vty
, pbrms
->nhg
->nexthop
,
856 pnhc
->nexthop
.ifindex
!= 0 ? pnhc
->intf_name
: NULL
);
857 if (pnhc
->nexthop
.vrf_id
!= VRF_DEFAULT
)
858 vty_out(vty
, " nexthop-vrf %s", pnhc
->vrf_name
);
863 static void vty_show_pbrms(struct vty
*vty
,
864 const struct pbr_map_sequence
*pbrms
, bool detail
)
869 pbr_map_reason_string(pbrms
->reason
, rbuf
, sizeof(rbuf
));
871 vty_out(vty
, " Seq: %u rule: %u\n", pbrms
->seqno
, pbrms
->ruleno
);
874 vty_out(vty
, " Installed: %" PRIu64
"(%u) Reason: %s\n",
875 pbrms
->installed
, pbrms
->unique
,
876 pbrms
->reason
? rbuf
: "Valid");
878 vty_out(vty
, " Installed: %s Reason: %s\n",
879 pbrms
->installed
? "yes" : "no",
880 pbrms
->reason
? rbuf
: "Valid");
882 if (pbrms
->ip_proto
) {
885 p
= getprotobynumber(pbrms
->ip_proto
);
886 vty_out(vty
, " IP Protocol Match: %s\n", p
->p_name
);
890 vty_out(vty
, " SRC IP Match: %pFX\n", pbrms
->src
);
892 vty_out(vty
, " DST IP Match: %pFX\n", pbrms
->dst
);
894 vty_out(vty
, " SRC Port Match: %u\n", pbrms
->src_prt
);
896 vty_out(vty
, " DST Port Match: %u\n", pbrms
->dst_prt
);
897 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
898 vty_out(vty
, " DSCP Match: %u\n",
899 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
900 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
901 vty_out(vty
, " ECN Match: %u\n",
902 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
904 vty_out(vty
, " MARK Match: %u\n", pbrms
->mark
);
906 if (pbrms
->action_queue_id
!= PBR_MAP_UNDEFINED_QUEUE_ID
)
907 vty_out(vty
, " Set Queue ID %u\n",
908 pbrms
->action_queue_id
);
910 if (pbrms
->action_vlan_id
!= 0)
911 vty_out(vty
, " Set VLAN ID %u\n", pbrms
->action_vlan_id
);
912 if (pbrms
->action_vlan_flags
== PBR_MAP_STRIP_INNER_ANY
)
913 vty_out(vty
, " Strip VLAN ID\n");
914 if (pbrms
->action_pcp
)
915 vty_out(vty
, " Set PCP %u\n", pbrms
->action_pcp
);
918 if (pbrms
->nhgrp_name
) {
919 vty_out(vty
, " Nexthop-Group: %s\n", pbrms
->nhgrp_name
);
923 " Installed: %u(%d) Tableid: %u\n",
924 pbrms
->nhs_installed
,
925 pbr_nht_get_installed(pbrms
->nhgrp_name
),
926 pbr_nht_get_table(pbrms
->nhgrp_name
));
928 vty_out(vty
, " Installed: %s Tableid: %u\n",
929 pbr_nht_get_installed(pbrms
->nhgrp_name
) ? "yes"
931 pbr_nht_get_table(pbrms
->nhgrp_name
));
933 } else if (pbrms
->nhg
) {
935 pbrms_nexthop_group_write_individual_nexthop(vty
, pbrms
);
938 " Installed: %u(%d) Tableid: %u\n",
939 pbrms
->nhs_installed
,
940 pbr_nht_get_installed(pbrms
->internal_nhg_name
),
941 pbr_nht_get_table(pbrms
->internal_nhg_name
));
943 vty_out(vty
, " Installed: %s Tableid: %u\n",
944 pbr_nht_get_installed(pbrms
->internal_nhg_name
)
947 pbr_nht_get_table(pbrms
->internal_nhg_name
));
949 } else if (pbrms
->vrf_unchanged
) {
950 vty_out(vty
, " VRF Unchanged (use interface vrf)\n");
951 } else if (pbrms
->vrf_lookup
) {
952 vty_out(vty
, " VRF Lookup: %s\n", pbrms
->vrf_name
);
954 vty_out(vty
, " Nexthop-Group: Unknown Installed: no\n");
958 static void vty_json_pbrms(json_object
*j
, struct vty
*vty
,
959 const struct pbr_map_sequence
*pbrms
)
961 json_object
*jpbrm
, *nexthop_group
;
962 char *nhg_name
= pbrms
->nhgrp_name
? pbrms
->nhgrp_name
963 : pbrms
->internal_nhg_name
;
966 jpbrm
= json_object_new_object();
968 json_object_int_add(jpbrm
, "id", pbrms
->unique
);
971 pbr_map_reason_string(pbrms
->reason
, rbuf
, sizeof(rbuf
));
973 json_object_int_add(jpbrm
, "sequenceNumber", pbrms
->seqno
);
974 json_object_int_add(jpbrm
, "ruleNumber", pbrms
->ruleno
);
975 json_object_boolean_add(jpbrm
, "vrfUnchanged", pbrms
->vrf_unchanged
);
976 json_object_boolean_add(jpbrm
, "installed",
977 pbr_nht_get_installed(nhg_name
));
978 json_object_string_add(jpbrm
, "installedReason",
979 pbrms
->reason
? rbuf
: "Valid");
982 nexthop_group
= json_object_new_object();
984 json_object_int_add(nexthop_group
, "tableId",
985 pbr_nht_get_table(nhg_name
));
986 json_object_string_add(nexthop_group
, "name", nhg_name
);
987 json_object_boolean_add(nexthop_group
, "installed",
988 pbr_nht_get_installed(nhg_name
));
989 json_object_int_add(nexthop_group
, "installedInternally",
990 pbrms
->nhs_installed
);
992 json_object_object_add(jpbrm
, "nexthopGroup", nexthop_group
);
995 if (pbrms
->vrf_lookup
)
996 json_object_string_add(jpbrm
, "vrfName", pbrms
->vrf_name
);
999 json_object_string_addf(jpbrm
, "matchSrc", "%pFX", pbrms
->src
);
1001 json_object_string_addf(jpbrm
, "matchDst", "%pFX", pbrms
->dst
);
1003 json_object_int_add(jpbrm
, "matchMark", pbrms
->mark
);
1004 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
1005 json_object_int_add(jpbrm
, "matchDscp",
1006 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
1007 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
1008 json_object_int_add(jpbrm
, "matchEcn",
1009 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
1011 json_object_array_add(j
, jpbrm
);
1014 static void vty_show_pbr_map(struct vty
*vty
, const struct pbr_map
*pbrm
,
1017 struct pbr_map_sequence
*pbrms
;
1018 struct listnode
*node
;
1020 vty_out(vty
, " pbr-map %s valid: %s\n", pbrm
->name
,
1021 pbrm
->valid
? "yes" : "no");
1023 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
1024 vty_show_pbrms(vty
, pbrms
, detail
);
1027 static void vty_json_pbr_map(json_object
*j
, struct vty
*vty
,
1028 const struct pbr_map
*pbrm
)
1030 struct pbr_map_sequence
*pbrms
;
1031 struct listnode
*node
;
1032 json_object
*jpbrms
;
1034 json_object_string_add(j
, "name", pbrm
->name
);
1035 json_object_boolean_add(j
, "valid", pbrm
->valid
);
1037 jpbrms
= json_object_new_array();
1039 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
1040 vty_json_pbrms(jpbrms
, vty
, pbrms
);
1042 json_object_object_add(j
, "policies", jpbrms
);
1045 DEFPY (show_pbr_map
,
1047 "show pbr map [NAME$name] [detail$detail|json$json]",
1052 "Detailed information\n"
1055 struct pbr_map
*pbrm
;
1056 json_object
*j
= NULL
;
1059 j
= json_object_new_array();
1061 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
1062 json_object
*this_map
= NULL
;
1063 if (name
&& strcmp(name
, pbrm
->name
) != 0)
1067 this_map
= json_object_new_object();
1070 vty_json_pbr_map(this_map
, vty
, pbrm
);
1072 json_object_array_add(j
, this_map
);
1076 vty_show_pbr_map(vty
, pbrm
, detail
);
1085 DEFPY(show_pbr_nexthop_group
,
1086 show_pbr_nexthop_group_cmd
,
1087 "show pbr nexthop-groups [WORD$word] [json$json]",
1091 "Optional Name of the nexthop group\n"
1094 json_object
*j
= NULL
;
1097 j
= json_object_new_array();
1100 pbr_nht_json_nexthop_group(j
, word
);
1104 pbr_nht_show_nexthop_group(vty
, word
);
1110 DEFPY (show_pbr_interface
,
1111 show_pbr_interface_cmd
,
1112 "show pbr interface [NAME$name] [json$json]",
1116 "PBR Interface Name\n"
1119 struct interface
*ifp
;
1121 struct pbr_interface
*pbr_ifp
;
1122 json_object
*j
= NULL
;
1125 j
= json_object_new_array();
1127 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
1128 FOR_ALL_INTERFACES(vrf
, ifp
) {
1129 struct pbr_map
*pbrm
;
1130 json_object
*this_iface
= NULL
;
1133 this_iface
= json_object_new_object();
1136 json_object_free(this_iface
);
1140 if (name
&& strcmp(ifp
->name
, name
) != 0) {
1141 json_object_free(this_iface
);
1145 pbr_ifp
= ifp
->info
;
1147 if (strcmp(pbr_ifp
->mapname
, "") == 0) {
1148 json_object_free(this_iface
);
1152 pbrm
= pbrm_find(pbr_ifp
->mapname
);
1155 json_object_string_add(this_iface
, "name",
1157 json_object_int_add(this_iface
, "index",
1159 json_object_string_add(this_iface
, "policy",
1161 json_object_boolean_add(this_iface
, "valid",
1164 json_object_array_add(j
, this_iface
);
1168 vty_out(vty
, " %s(%d) with pbr-policy %s", ifp
->name
,
1169 ifp
->ifindex
, pbr_ifp
->mapname
);
1171 vty_out(vty
, " (map doesn't exist)");
1182 /* PBR debugging CLI ------------------------------------------------------- */
1184 static struct cmd_node debug_node
= {
1188 .config_write
= pbr_debug_config_write
,
1193 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
1198 "PBRD <-> Zebra communications\n"
1199 "Nexthop tracking\n"
1202 uint32_t mode
= DEBUG_NODE2MODE(vty
->node
);
1205 DEBUG_MODE_SET(&pbr_dbg_map
, mode
, !no
);
1207 DEBUG_MODE_SET(&pbr_dbg_zebra
, mode
, !no
);
1209 DEBUG_MODE_SET(&pbr_dbg_nht
, mode
, !no
);
1211 DEBUG_MODE_SET(&pbr_dbg_event
, mode
, !no
);
1213 /* no specific debug --> act on all of them */
1214 if (strmatch(argv
[argc
- 1]->text
, "pbr"))
1215 pbr_debug_set_all(mode
, !no
);
1220 DEFUN_NOSH(show_debugging_pbr
,
1221 show_debugging_pbr_cmd
,
1222 "show debugging [pbr]",
1227 vty_out(vty
, "PBR debugging status:\n");
1229 pbr_debug_config_write_helper(vty
, false);
1231 cmd_show_lib_debugs(vty
);
1236 /* ------------------------------------------------------------------------- */
1239 static int pbr_interface_config_write(struct vty
*vty
)
1241 struct interface
*ifp
;
1244 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1245 FOR_ALL_INTERFACES (vrf
, ifp
) {
1246 if_vty_config_start(vty
, ifp
);
1249 vty_out(vty
, " description %s\n", ifp
->desc
);
1251 pbr_map_write_interfaces(vty
, ifp
);
1253 if_vty_config_end(vty
);
1260 static int pbr_vty_map_config_write(struct vty
*vty
);
1261 /* PBR map node structure. */
1262 static struct cmd_node pbr_map_node
= {
1264 .node
= PBRMAP_NODE
,
1265 .parent_node
= CONFIG_NODE
,
1266 .prompt
= "%s(config-pbr-map)# ",
1267 .config_write
= pbr_vty_map_config_write
,
1270 static int pbr_vty_map_config_write_sequence(struct vty
*vty
,
1271 struct pbr_map
*pbrm
,
1272 struct pbr_map_sequence
*pbrms
)
1274 vty_out(vty
, "pbr-map %s seq %u\n", pbrm
->name
, pbrms
->seqno
);
1277 vty_out(vty
, " match src-ip %pFX\n", pbrms
->src
);
1280 vty_out(vty
, " match dst-ip %pFX\n", pbrms
->dst
);
1283 vty_out(vty
, " match src-port %u\n", pbrms
->src_prt
);
1285 vty_out(vty
, " match dst-port %u\n", pbrms
->dst_prt
);
1287 if (pbrms
->ip_proto
) {
1290 p
= getprotobynumber(pbrms
->ip_proto
);
1291 vty_out(vty
, " match ip-protocol %s\n", p
->p_name
);
1294 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
1295 vty_out(vty
, " match dscp %u\n",
1296 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
1298 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
1299 vty_out(vty
, " match ecn %u\n",
1300 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
1303 vty_out(vty
, " match mark %u\n", pbrms
->mark
);
1306 if (pbrms
->action_queue_id
!= PBR_MAP_UNDEFINED_QUEUE_ID
)
1307 vty_out(vty
, " set queue-id %d\n", pbrms
->action_queue_id
);
1309 if (pbrms
->action_pcp
)
1310 vty_out(vty
, " set pcp %d\n", pbrms
->action_pcp
);
1312 if (pbrms
->action_vlan_id
)
1313 vty_out(vty
, " set vlan %u\n", pbrms
->action_vlan_id
);
1315 if (pbrms
->action_vlan_flags
== PBR_MAP_STRIP_INNER_ANY
)
1316 vty_out(vty
, " strip vlan any\n");
1318 if (pbrms
->vrf_unchanged
)
1319 vty_out(vty
, " set vrf unchanged\n");
1321 if (pbrms
->vrf_lookup
)
1322 vty_out(vty
, " set vrf %s\n", pbrms
->vrf_name
);
1324 if (pbrms
->nhgrp_name
)
1325 vty_out(vty
, " set nexthop-group %s\n", pbrms
->nhgrp_name
);
1328 vty_out(vty
, " set ");
1329 pbrms_nexthop_group_write_individual_nexthop(vty
, pbrms
);
1332 vty_out(vty
, "exit\n");
1333 vty_out(vty
, "!\n");
1337 static int pbr_vty_map_config_write(struct vty
*vty
)
1339 struct pbr_map
*pbrm
;
1341 pbr_nht_write_table_range(vty
);
1342 pbr_nht_write_rule_range(vty
);
1344 RB_FOREACH(pbrm
, pbr_map_entry_head
, &pbr_maps
) {
1345 struct pbr_map_sequence
*pbrms
;
1346 struct listnode
*node
;
1348 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
1349 pbr_vty_map_config_write_sequence(vty
, pbrm
, pbrms
);
1355 static void pbr_map_completer(vector comps
, struct cmd_token
*token
)
1357 struct pbr_map
*pbrm
;
1359 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
)
1360 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, pbrm
->name
));
1363 static const struct cmd_variable_handler pbr_map_name
[] = {
1365 .tokenname
= "PBRMAP", .completions
= pbr_map_completer
,
1372 extern struct zebra_privs_t pbr_privs
;
1374 void pbr_vty_init(void)
1376 cmd_variable_handler_register(pbr_map_name
);
1380 if_cmd_init(pbr_interface_config_write
);
1382 install_node(&pbr_map_node
);
1385 install_node(&debug_node
);
1386 install_element(ENABLE_NODE
, &debug_pbr_cmd
);
1387 install_element(CONFIG_NODE
, &debug_pbr_cmd
);
1388 install_element(ENABLE_NODE
, &show_debugging_pbr_cmd
);
1390 install_default(PBRMAP_NODE
);
1392 install_element(CONFIG_NODE
, &pbr_map_cmd
);
1393 install_element(CONFIG_NODE
, &no_pbr_map_cmd
);
1394 install_element(CONFIG_NODE
, &pbr_set_table_range_cmd
);
1395 install_element(CONFIG_NODE
, &no_pbr_set_table_range_cmd
);
1396 install_element(INTERFACE_NODE
, &pbr_policy_cmd
);
1397 install_element(PBRMAP_NODE
, &pbr_map_match_ip_proto_cmd
);
1398 install_element(PBRMAP_NODE
, &pbr_map_match_src_port_cmd
);
1399 install_element(PBRMAP_NODE
, &pbr_map_match_dst_port_cmd
);
1400 install_element(PBRMAP_NODE
, &pbr_map_match_src_cmd
);
1401 install_element(PBRMAP_NODE
, &pbr_map_match_dst_cmd
);
1402 install_element(PBRMAP_NODE
, &pbr_map_match_dscp_cmd
);
1403 install_element(PBRMAP_NODE
, &pbr_map_match_ecn_cmd
);
1404 install_element(PBRMAP_NODE
, &pbr_map_match_mark_cmd
);
1405 install_element(PBRMAP_NODE
, &pbr_map_action_queue_id_cmd
);
1406 install_element(PBRMAP_NODE
, &pbr_map_action_strip_vlan_cmd
);
1407 install_element(PBRMAP_NODE
, &pbr_map_action_vlan_id_cmd
);
1408 install_element(PBRMAP_NODE
, &pbr_map_action_pcp_cmd
);
1409 install_element(PBRMAP_NODE
, &pbr_map_nexthop_group_cmd
);
1410 install_element(PBRMAP_NODE
, &no_pbr_map_nexthop_group_cmd
);
1411 install_element(PBRMAP_NODE
, &pbr_map_nexthop_cmd
);
1412 install_element(PBRMAP_NODE
, &no_pbr_map_nexthop_cmd
);
1413 install_element(PBRMAP_NODE
, &pbr_map_vrf_cmd
);
1414 install_element(PBRMAP_NODE
, &no_pbr_map_vrf_cmd
);
1415 install_element(VIEW_NODE
, &show_pbr_cmd
);
1416 install_element(VIEW_NODE
, &show_pbr_map_cmd
);
1417 install_element(VIEW_NODE
, &show_pbr_interface_cmd
);
1418 install_element(VIEW_NODE
, &show_pbr_nexthop_group_cmd
);