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 pbrms
->family
= prefix
->family
;
144 if (prefix_same(pbrms
->src
, prefix
))
147 pbrms
->src
= prefix_new();
149 prefix_copy(pbrms
->src
, prefix
);
151 prefix_free(&pbrms
->src
);
153 pbr_map_check(pbrms
, true);
158 DEFPY(pbr_map_match_dst
, pbr_map_match_dst_cmd
,
159 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
161 "Match the rest of the command\n"
162 "Choose the dst ip or ipv6 prefix to use\n"
166 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
168 pbrms
->family
= prefix
->family
;
172 if (prefix_same(pbrms
->dst
, prefix
))
175 pbrms
->dst
= prefix_new();
177 prefix_copy(pbrms
->dst
, prefix
);
179 prefix_free(&pbrms
->dst
);
181 pbr_map_check(pbrms
, true);
186 DEFPY(pbr_map_match_dscp
, pbr_map_match_dscp_cmd
,
187 "[no] match dscp DSCP$dscp",
189 "Match the rest of the command\n"
190 "Match based on IP DSCP field\n"
191 "DSCP value (below 64) or standard codepoint name\n")
193 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
197 /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
198 bool isANumber
= true;
199 for (int i
= 0; i
< (int)strlen(dscp
); i
++) {
200 /* Letters are not numbers */
201 if (!isdigit(dscp
[i
]))
204 /* Lowercase the dscp enum (if needed) */
205 if (isupper(dscp
[i
]))
206 dscpname
[i
] = tolower(dscp
[i
]);
208 dscpname
[i
] = dscp
[i
];
210 dscpname
[strlen(dscp
)] = '\0';
213 /* dscp passed is a regular number */
214 long dscpAsNum
= strtol(dscp
, NULL
, 0);
216 if (dscpAsNum
> PBR_DSFIELD_DSCP
>> 2) {
217 /* Refuse to install on overflow */
218 vty_out(vty
, "dscp (%s) must be less than 64\n", dscp
);
219 return CMD_WARNING_CONFIG_FAILED
;
223 /* check dscp if it is an enum like cs0 */
224 rawDscp
= pbr_map_decode_dscp_enum(dscpname
);
225 if (rawDscp
> PBR_DSFIELD_DSCP
) {
226 vty_out(vty
, "Invalid dscp value: %s\n", dscpname
);
227 return CMD_WARNING_CONFIG_FAILED
;
232 if (((pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2) == rawDscp
)
235 /* Set the DSCP bits of the DSField */
237 (pbrms
->dsfield
& ~PBR_DSFIELD_DSCP
) | (rawDscp
<< 2);
239 pbrms
->dsfield
&= ~PBR_DSFIELD_DSCP
;
242 pbr_map_check(pbrms
, true);
247 DEFPY(pbr_map_match_ecn
, pbr_map_match_ecn_cmd
,
248 "[no] match ecn (0-3)$ecn",
250 "Match the rest of the command\n"
251 "Match based on IP ECN field\n"
252 "Explicit Congestion Notification\n")
254 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
257 if ((pbrms
->dsfield
& PBR_DSFIELD_ECN
) == ecn
)
260 /* Set the ECN bits of the DSField */
261 pbrms
->dsfield
= (pbrms
->dsfield
& ~PBR_DSFIELD_ECN
) | ecn
;
263 pbrms
->dsfield
&= ~PBR_DSFIELD_ECN
;
266 pbr_map_check(pbrms
, true);
271 DEFPY(pbr_map_match_mark
, pbr_map_match_mark_cmd
,
272 "[no] match mark (1-4294967295)$mark",
274 "Match the rest of the command\n"
275 "Choose the mark value to use\n"
278 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
281 vty_out(vty
, "pbr marks are not supported on this platform");
282 return CMD_WARNING_CONFIG_FAILED
;
287 if (pbrms
->mark
== (uint32_t)mark
)
290 pbrms
->mark
= (uint32_t)mark
;
294 pbr_map_check(pbrms
, true);
299 static void pbrms_clear_set_vrf_config(struct pbr_map_sequence
*pbrms
)
301 if (pbrms
->vrf_lookup
|| pbrms
->vrf_unchanged
) {
302 pbr_map_delete_vrf(pbrms
);
303 pbrms
->vrf_name
[0] = '\0';
304 pbrms
->vrf_lookup
= false;
305 pbrms
->vrf_unchanged
= false;
309 static void pbrms_clear_set_nhg_config(struct pbr_map_sequence
*pbrms
)
311 if (pbrms
->nhgrp_name
)
312 pbr_map_delete_nexthops(pbrms
);
315 static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence
*pbrms
)
318 pbr_nht_delete_individual_nexthop(pbrms
);
321 static void pbrms_clear_set_config(struct pbr_map_sequence
*pbrms
)
323 pbrms_clear_set_vrf_config(pbrms
);
324 pbrms_clear_set_nhg_config(pbrms
);
325 pbrms_clear_set_nexthop_config(pbrms
);
327 pbrms
->nhs_installed
= false;
330 DEFPY(pbr_map_nexthop_group
, pbr_map_nexthop_group_cmd
,
331 "set nexthop-group NHGNAME$name",
332 "Set for the PBR-MAP\n"
333 "nexthop-group to use\n"
334 "The name of the nexthop-group\n")
336 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
337 struct nexthop_group_cmd
*nhgc
;
339 nhgc
= nhgc_find(name
);
341 vty_out(vty
, "Specified nexthop-group %s does not exist\n",
344 "PBR-MAP will not be applied until it is created\n");
347 if (pbrms
->nhgrp_name
&& strcmp(name
, pbrms
->nhgrp_name
) == 0)
350 /* This is new/replacement config */
351 pbrms_clear_set_config(pbrms
);
353 pbrms
->nhgrp_name
= XSTRDUP(MTYPE_TMP
, name
);
354 pbr_map_check(pbrms
, true);
359 DEFPY(no_pbr_map_nexthop_group
, no_pbr_map_nexthop_group_cmd
,
360 "no set nexthop-group [NHGNAME$name]",
362 "Set for the PBR-MAP\n"
363 "nexthop-group to use\n"
364 "The name of the nexthop-group\n")
366 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
368 pbrms_clear_set_config(pbrms
);
373 DEFPY(pbr_map_nexthop
, pbr_map_nexthop_cmd
,
376 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
379 [nexthop-vrf NAME$vrf_name]",
380 "Set for the PBR-MAP\n"
381 "Specify one of the nexthops in this map\n"
386 "If the nexthop is in a different vrf tell us\n"
387 "The nexthop-vrf Name\n")
389 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
392 struct nexthop
*nh
= NULL
;
395 vrf
= vrf_lookup_by_name(vrf_name
);
397 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
400 vty_out(vty
, "Specified VRF: %s is non-existent\n", vrf_name
);
401 return CMD_WARNING_CONFIG_FAILED
;
404 memset(&nhop
, 0, sizeof(nhop
));
405 nhop
.vrf_id
= vrf
->vrf_id
;
408 struct interface
*ifp
;
410 ifp
= if_lookup_by_name_all_vrf(intf
);
412 vty_out(vty
, "Specified Intf %s does not exist\n",
414 return CMD_WARNING_CONFIG_FAILED
;
416 if (ifp
->vrf_id
!= vrf
->vrf_id
) {
419 actual
= vrf_lookup_by_id(ifp
->vrf_id
);
421 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
422 ifp
->name
, vrf
->name
, actual
->name
);
424 nhop
.ifindex
= ifp
->ifindex
;
425 nhop
.vrf_id
= ifp
->vrf_id
;
429 if (addr
->sa
.sa_family
== AF_INET
) {
430 nhop
.gate
.ipv4
.s_addr
= addr
->sin
.sin_addr
.s_addr
;
432 nhop
.type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
434 nhop
.type
= NEXTHOP_TYPE_IPV4
;
436 nhop
.gate
.ipv6
= addr
->sin6
.sin6_addr
;
438 nhop
.type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
440 if (IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
)) {
442 "Specified a v6 LL with no interface, rejecting\n");
443 return CMD_WARNING_CONFIG_FAILED
;
445 nhop
.type
= NEXTHOP_TYPE_IPV6
;
449 nhop
.type
= NEXTHOP_TYPE_IFINDEX
;
452 nh
= nexthop_exists(pbrms
->nhg
, &nhop
);
454 if (nh
) /* Same config re-entered */
457 /* This is new/replacement config */
458 pbrms_clear_set_config(pbrms
);
460 pbr_nht_add_individual_nexthop(pbrms
, &nhop
);
462 pbr_map_check(pbrms
, true);
465 if (nhop
.type
== NEXTHOP_TYPE_IFINDEX
466 || (nhop
.type
== NEXTHOP_TYPE_IPV6_IFINDEX
467 && IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
))) {
468 struct interface
*ifp
;
470 ifp
= if_lookup_by_index(nhop
.ifindex
, nhop
.vrf_id
);
472 pbr_nht_nexthop_interface_update(ifp
);
478 DEFPY(no_pbr_map_nexthop
, no_pbr_map_nexthop_cmd
,
481 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
484 [nexthop-vrf NAME$vrf_name]]",
486 "Set for the PBR-MAP\n"
487 "Specify one of the nexthops in this map\n"
492 "If the nexthop is in a different vrf tell us\n"
493 "The nexthop-vrf Name\n")
495 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
497 pbrms_clear_set_config(pbrms
);
502 DEFPY(pbr_map_vrf
, pbr_map_vrf_cmd
,
503 "set vrf <NAME$vrf_name|unchanged>",
504 "Set for the PBR-MAP\n"
505 "Specify the VRF for this map\n"
507 "Use the interface's VRF for lookup\n")
509 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
512 * If an equivalent set vrf * exists, just return success.
514 if (vrf_name
&& pbrms
->vrf_lookup
515 && strncmp(pbrms
->vrf_name
, vrf_name
, sizeof(pbrms
->vrf_name
)) == 0)
517 else if (!vrf_name
&& pbrms
->vrf_unchanged
) /* Unchanged already set */
520 if (vrf_name
&& !pbr_vrf_lookup_by_name(vrf_name
)) {
521 vty_out(vty
, "Specified: %s is non-existent\n", vrf_name
);
522 return CMD_WARNING_CONFIG_FAILED
;
525 /* This is new/replacement config */
526 pbrms_clear_set_config(pbrms
);
529 pbrms
->vrf_lookup
= true;
530 strlcpy(pbrms
->vrf_name
, vrf_name
, sizeof(pbrms
->vrf_name
));
532 pbrms
->vrf_unchanged
= true;
534 pbr_map_check(pbrms
, true);
539 DEFPY(no_pbr_map_vrf
, no_pbr_map_vrf_cmd
,
540 "no set vrf [<NAME$vrf_name|unchanged>]",
542 "Set for the PBR-MAP\n"
543 "Specify the VRF for this map\n"
545 "Use the interface's VRF for lookup\n")
547 struct pbr_map_sequence
*pbrms
= VTY_GET_CONTEXT(pbr_map_sequence
);
549 pbrms_clear_set_config(pbrms
);
556 "[no] pbr-policy PBRMAP$mapname",
559 "Name of the pbr-map to apply\n")
561 VTY_DECLVAR_CONTEXT(interface
, ifp
);
562 struct pbr_map
*pbrm
, *old_pbrm
;
563 struct pbr_interface
*pbr_ifp
= ifp
->info
;
566 pbrm
= pbrm_find(mapname
);
569 /* we don't want one and we don't have one, so... */
573 /* Some one could have fat fingered the interface name */
574 pbr_ifp
= pbr_if_new(ifp
);
578 if (strcmp(pbr_ifp
->mapname
, mapname
) == 0) {
579 pbr_ifp
->mapname
[0] = '\0';
581 pbr_map_interface_delete(pbrm
, ifp
);
584 if (strcmp(pbr_ifp
->mapname
, "") != 0) {
585 old_pbrm
= pbrm_find(pbr_ifp
->mapname
);
588 * So if we have an old pbrm we should only
589 * delete it if we are actually deleting and
590 * moving to a new pbrm
592 if (old_pbrm
&& old_pbrm
!= pbrm
)
593 pbr_map_interface_delete(old_pbrm
, ifp
);
595 snprintf(pbr_ifp
->mapname
, sizeof(pbr_ifp
->mapname
),
599 * So only reinstall if the old_pbrm and this pbrm are
602 if (pbrm
&& pbrm
!= old_pbrm
)
603 pbr_map_add_interface(pbrm
, ifp
);
615 pbr_nht_write_table_range(vty
);
616 pbr_nht_write_rule_range(vty
);
622 pbrms_nexthop_group_write_individual_nexthop(
623 struct vty
*vty
, const struct pbr_map_sequence
*pbrms
)
625 struct pbr_nexthop_group_cache find
;
626 struct pbr_nexthop_group_cache
*pnhgc
;
627 struct pbr_nexthop_cache lookup
;
628 struct pbr_nexthop_cache
*pnhc
;
630 memset(&find
, 0, sizeof(find
));
631 strlcpy(find
.name
, pbrms
->internal_nhg_name
, sizeof(find
.name
));
633 pnhgc
= hash_lookup(pbr_nhg_hash
, &find
);
636 lookup
.nexthop
= *pbrms
->nhg
->nexthop
;
637 pnhc
= hash_lookup(pnhgc
->nhh
, &lookup
);
639 nexthop_group_write_nexthop_simple(
640 vty
, pbrms
->nhg
->nexthop
,
641 pnhc
->nexthop
.ifindex
!= 0 ? pnhc
->intf_name
: NULL
);
642 if (pnhc
->nexthop
.vrf_id
!= VRF_DEFAULT
)
643 vty_out(vty
, " nexthop-vrf %s", pnhc
->vrf_name
);
648 static void vty_show_pbrms(struct vty
*vty
,
649 const struct pbr_map_sequence
*pbrms
, bool detail
)
651 char buf
[PREFIX_STRLEN
];
655 pbr_map_reason_string(pbrms
->reason
, rbuf
, sizeof(rbuf
));
657 vty_out(vty
, " Seq: %u rule: %u\n", pbrms
->seqno
, pbrms
->ruleno
);
660 vty_out(vty
, " Installed: %" PRIu64
"(%u) Reason: %s\n",
661 pbrms
->installed
, pbrms
->unique
,
662 pbrms
->reason
? rbuf
: "Valid");
664 vty_out(vty
, " Installed: %s Reason: %s\n",
665 pbrms
->installed
? "yes" : "no",
666 pbrms
->reason
? rbuf
: "Valid");
669 vty_out(vty
, " SRC Match: %s\n",
670 prefix2str(pbrms
->src
, buf
, sizeof(buf
)));
672 vty_out(vty
, " DST Match: %s\n",
673 prefix2str(pbrms
->dst
, buf
, sizeof(buf
)));
674 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
675 vty_out(vty
, " DSCP Match: %u\n",
676 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
677 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
678 vty_out(vty
, " ECN Match: %u\n",
679 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
681 vty_out(vty
, " MARK Match: %u\n", pbrms
->mark
);
683 if (pbrms
->nhgrp_name
) {
684 vty_out(vty
, " Nexthop-Group: %s\n", pbrms
->nhgrp_name
);
688 " Installed: %u(%d) Tableid: %d\n",
689 pbrms
->nhs_installed
,
690 pbr_nht_get_installed(pbrms
->nhgrp_name
),
691 pbr_nht_get_table(pbrms
->nhgrp_name
));
693 vty_out(vty
, " Installed: %s Tableid: %d\n",
694 pbr_nht_get_installed(pbrms
->nhgrp_name
) ? "yes"
696 pbr_nht_get_table(pbrms
->nhgrp_name
));
698 } else if (pbrms
->nhg
) {
700 pbrms_nexthop_group_write_individual_nexthop(vty
, pbrms
);
703 " Installed: %u(%d) Tableid: %d\n",
704 pbrms
->nhs_installed
,
705 pbr_nht_get_installed(pbrms
->internal_nhg_name
),
706 pbr_nht_get_table(pbrms
->internal_nhg_name
));
708 vty_out(vty
, " Installed: %s Tableid: %d\n",
709 pbr_nht_get_installed(pbrms
->internal_nhg_name
)
712 pbr_nht_get_table(pbrms
->internal_nhg_name
));
714 } else if (pbrms
->vrf_unchanged
) {
715 vty_out(vty
, " VRF Unchanged (use interface vrf)\n");
716 } else if (pbrms
->vrf_lookup
) {
717 vty_out(vty
, " VRF Lookup: %s\n", pbrms
->vrf_name
);
719 vty_out(vty
, " Nexthop-Group: Unknown Installed: no\n");
723 static void vty_json_pbrms(json_object
*j
, struct vty
*vty
,
724 const struct pbr_map_sequence
*pbrms
)
726 json_object
*jpbrm
, *nexthop_group
;
727 char *nhg_name
= pbrms
->nhgrp_name
? pbrms
->nhgrp_name
728 : pbrms
->internal_nhg_name
;
729 char buf
[PREFIX_STRLEN
];
732 jpbrm
= json_object_new_object();
734 json_object_int_add(jpbrm
, "id", pbrms
->unique
);
737 pbr_map_reason_string(pbrms
->reason
, rbuf
, sizeof(rbuf
));
739 json_object_int_add(jpbrm
, "sequenceNumber", pbrms
->seqno
);
740 json_object_int_add(jpbrm
, "ruleNumber", pbrms
->ruleno
);
741 json_object_boolean_add(jpbrm
, "vrfUnchanged", pbrms
->vrf_unchanged
);
742 json_object_boolean_add(jpbrm
, "installed",
743 pbr_nht_get_installed(nhg_name
));
744 json_object_string_add(jpbrm
, "installedReason",
745 pbrms
->reason
? rbuf
: "Valid");
748 nexthop_group
= json_object_new_object();
750 json_object_int_add(nexthop_group
, "tableId",
751 pbr_nht_get_table(nhg_name
));
752 json_object_string_add(nexthop_group
, "name", nhg_name
);
753 json_object_boolean_add(nexthop_group
, "installed",
754 pbr_nht_get_installed(nhg_name
));
755 json_object_int_add(nexthop_group
, "installedInternally",
756 pbrms
->nhs_installed
);
758 json_object_object_add(jpbrm
, "nexthopGroup", nexthop_group
);
761 if (pbrms
->vrf_lookup
)
762 json_object_string_add(jpbrm
, "vrfName", pbrms
->vrf_name
);
765 json_object_string_add(
767 prefix2str(pbrms
->src
, buf
, sizeof(buf
)));
769 json_object_string_add(
771 prefix2str(pbrms
->dst
, buf
, sizeof(buf
)));
773 json_object_int_add(jpbrm
, "matchMark", pbrms
->mark
);
774 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
775 json_object_int_add(jpbrm
, "matchDscp",
776 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
777 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
778 json_object_int_add(jpbrm
, "matchEcn",
779 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
781 json_object_array_add(j
, jpbrm
);
784 static void vty_show_pbr_map(struct vty
*vty
, const struct pbr_map
*pbrm
,
787 struct pbr_map_sequence
*pbrms
;
788 struct listnode
*node
;
790 vty_out(vty
, " pbr-map %s valid: %s\n", pbrm
->name
,
791 pbrm
->valid
? "yes" : "no");
793 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
794 vty_show_pbrms(vty
, pbrms
, detail
);
797 static void vty_json_pbr_map(json_object
*j
, struct vty
*vty
,
798 const struct pbr_map
*pbrm
)
800 struct pbr_map_sequence
*pbrms
;
801 struct listnode
*node
;
804 json_object_string_add(j
, "name", pbrm
->name
);
805 json_object_boolean_add(j
, "valid", pbrm
->valid
);
807 jpbrms
= json_object_new_array();
809 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
810 vty_json_pbrms(jpbrms
, vty
, pbrms
);
812 json_object_object_add(j
, "policies", jpbrms
);
817 "show pbr map [NAME$name] [detail$detail|json$json]",
822 "Detailed information\n"
825 struct pbr_map
*pbrm
;
826 json_object
*j
= NULL
;
829 j
= json_object_new_array();
831 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
) {
832 json_object
*this_map
= NULL
;
833 if (name
&& strcmp(name
, pbrm
->name
) != 0)
837 this_map
= json_object_new_object();
840 vty_json_pbr_map(this_map
, vty
, pbrm
);
842 json_object_array_add(j
, this_map
);
846 vty_show_pbr_map(vty
, pbrm
, detail
);
851 json_object_to_json_string_ext(
852 j
, JSON_C_TO_STRING_PRETTY
));
859 DEFPY(show_pbr_nexthop_group
,
860 show_pbr_nexthop_group_cmd
,
861 "show pbr nexthop-groups [WORD$word] [json$json]",
865 "Optional Name of the nexthop group\n"
868 json_object
*j
= NULL
;
871 j
= json_object_new_array();
874 pbr_nht_json_nexthop_group(j
, word
);
877 json_object_to_json_string_ext(
878 j
, JSON_C_TO_STRING_PRETTY
));
882 pbr_nht_show_nexthop_group(vty
, word
);
888 DEFPY (show_pbr_interface
,
889 show_pbr_interface_cmd
,
890 "show pbr interface [NAME$name] [json$json]",
894 "PBR Interface Name\n"
897 struct interface
*ifp
;
899 struct pbr_interface
*pbr_ifp
;
900 json_object
*j
= NULL
;
903 j
= json_object_new_array();
905 RB_FOREACH(vrf
, vrf_name_head
, &vrfs_by_name
) {
906 FOR_ALL_INTERFACES(vrf
, ifp
) {
907 struct pbr_map
*pbrm
;
908 json_object
*this_iface
= NULL
;
911 this_iface
= json_object_new_object();
916 if (name
&& strcmp(ifp
->name
, name
) != 0)
921 if (strcmp(pbr_ifp
->mapname
, "") == 0)
924 pbrm
= pbrm_find(pbr_ifp
->mapname
);
927 json_object_string_add(this_iface
, "name",
929 json_object_int_add(this_iface
, "index",
931 json_object_string_add(this_iface
, "policy",
933 json_object_boolean_add(this_iface
, "valid",
936 json_object_array_add(j
, this_iface
);
940 vty_out(vty
, " %s(%d) with pbr-policy %s", ifp
->name
,
941 ifp
->ifindex
, pbr_ifp
->mapname
);
943 vty_out(vty
, " (map doesn't exist)");
950 json_object_to_json_string_ext(
951 j
, JSON_C_TO_STRING_PRETTY
));
958 /* PBR debugging CLI ------------------------------------------------------- */
960 static struct cmd_node debug_node
= {
964 .config_write
= pbr_debug_config_write
,
969 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
974 "PBRD <-> Zebra communications\n"
978 uint32_t mode
= DEBUG_NODE2MODE(vty
->node
);
981 DEBUG_MODE_SET(&pbr_dbg_map
, mode
, !no
);
983 DEBUG_MODE_SET(&pbr_dbg_zebra
, mode
, !no
);
985 DEBUG_MODE_SET(&pbr_dbg_nht
, mode
, !no
);
987 DEBUG_MODE_SET(&pbr_dbg_event
, mode
, !no
);
989 /* no specific debug --> act on all of them */
990 if (strmatch(argv
[argc
- 1]->text
, "pbr"))
991 pbr_debug_set_all(mode
, !no
);
996 DEFUN_NOSH(show_debugging_pbr
,
997 show_debugging_pbr_cmd
,
998 "show debugging [pbr]",
1003 vty_out(vty
, "PBR debugging status:\n");
1005 pbr_debug_config_write_helper(vty
, false);
1010 /* ------------------------------------------------------------------------- */
1013 static int pbr_interface_config_write(struct vty
*vty
);
1014 static struct cmd_node interface_node
= {
1015 .name
= "interface",
1016 .node
= INTERFACE_NODE
,
1017 .parent_node
= CONFIG_NODE
,
1018 .prompt
= "%s(config-if)# ",
1019 .config_write
= pbr_interface_config_write
,
1022 static int pbr_interface_config_write(struct vty
*vty
)
1024 struct interface
*ifp
;
1027 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
1028 FOR_ALL_INTERFACES (vrf
, ifp
) {
1029 if (vrf
->vrf_id
== VRF_DEFAULT
)
1030 vty_frame(vty
, "interface %s\n", ifp
->name
);
1032 vty_frame(vty
, "interface %s vrf %s\n",
1033 ifp
->name
, vrf
->name
);
1036 vty_out(vty
, " description %s\n", ifp
->desc
);
1038 pbr_map_write_interfaces(vty
, ifp
);
1040 vty_endframe(vty
, "!\n");
1047 static int pbr_vty_map_config_write(struct vty
*vty
);
1048 /* PBR map node structure. */
1049 static struct cmd_node pbr_map_node
= {
1051 .node
= PBRMAP_NODE
,
1052 .parent_node
= CONFIG_NODE
,
1053 .prompt
= "%s(config-pbr-map)# ",
1054 .config_write
= pbr_vty_map_config_write
,
1057 static int pbr_vty_map_config_write_sequence(struct vty
*vty
,
1058 struct pbr_map
*pbrm
,
1059 struct pbr_map_sequence
*pbrms
)
1061 char buff
[PREFIX_STRLEN
];
1063 vty_out(vty
, "pbr-map %s seq %u\n", pbrm
->name
, pbrms
->seqno
);
1066 vty_out(vty
, " match src-ip %s\n",
1067 prefix2str(pbrms
->src
, buff
, sizeof(buff
)));
1070 vty_out(vty
, " match dst-ip %s\n",
1071 prefix2str(pbrms
->dst
, buff
, sizeof(buff
)));
1073 if (pbrms
->dsfield
& PBR_DSFIELD_DSCP
)
1074 vty_out(vty
, " match dscp %u\n",
1075 (pbrms
->dsfield
& PBR_DSFIELD_DSCP
) >> 2);
1077 if (pbrms
->dsfield
& PBR_DSFIELD_ECN
)
1078 vty_out(vty
, " match ecn %u\n",
1079 pbrms
->dsfield
& PBR_DSFIELD_ECN
);
1082 vty_out(vty
, " match mark %u\n", pbrms
->mark
);
1084 if (pbrms
->vrf_unchanged
)
1085 vty_out(vty
, " set vrf unchanged\n");
1087 if (pbrms
->vrf_lookup
)
1088 vty_out(vty
, " set vrf %s\n", pbrms
->vrf_name
);
1090 if (pbrms
->nhgrp_name
)
1091 vty_out(vty
, " set nexthop-group %s\n", pbrms
->nhgrp_name
);
1094 vty_out(vty
, " set ");
1095 pbrms_nexthop_group_write_individual_nexthop(vty
, pbrms
);
1098 vty_out(vty
, "!\n");
1102 static int pbr_vty_map_config_write(struct vty
*vty
)
1104 struct pbr_map
*pbrm
;
1106 pbr_nht_write_table_range(vty
);
1107 pbr_nht_write_rule_range(vty
);
1109 RB_FOREACH(pbrm
, pbr_map_entry_head
, &pbr_maps
) {
1110 struct pbr_map_sequence
*pbrms
;
1111 struct listnode
*node
;
1113 for (ALL_LIST_ELEMENTS_RO(pbrm
->seqnumbers
, node
, pbrms
))
1114 pbr_vty_map_config_write_sequence(vty
, pbrm
, pbrms
);
1120 static void pbr_map_completer(vector comps
, struct cmd_token
*token
)
1122 struct pbr_map
*pbrm
;
1124 RB_FOREACH (pbrm
, pbr_map_entry_head
, &pbr_maps
)
1125 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, pbrm
->name
));
1128 static const struct cmd_variable_handler pbr_map_name
[] = {
1130 .tokenname
= "PBRMAP", .completions
= pbr_map_completer
,
1137 void pbr_vty_init(void)
1139 cmd_variable_handler_register(pbr_map_name
);
1141 install_node(&interface_node
);
1144 install_node(&pbr_map_node
);
1147 install_node(&debug_node
);
1148 install_element(VIEW_NODE
, &debug_pbr_cmd
);
1149 install_element(CONFIG_NODE
, &debug_pbr_cmd
);
1150 install_element(VIEW_NODE
, &show_debugging_pbr_cmd
);
1152 install_default(PBRMAP_NODE
);
1154 install_element(CONFIG_NODE
, &pbr_map_cmd
);
1155 install_element(CONFIG_NODE
, &no_pbr_map_cmd
);
1156 install_element(CONFIG_NODE
, &pbr_set_table_range_cmd
);
1157 install_element(CONFIG_NODE
, &no_pbr_set_table_range_cmd
);
1158 install_element(INTERFACE_NODE
, &pbr_policy_cmd
);
1159 install_element(PBRMAP_NODE
, &pbr_map_match_src_cmd
);
1160 install_element(PBRMAP_NODE
, &pbr_map_match_dst_cmd
);
1161 install_element(PBRMAP_NODE
, &pbr_map_match_dscp_cmd
);
1162 install_element(PBRMAP_NODE
, &pbr_map_match_ecn_cmd
);
1163 install_element(PBRMAP_NODE
, &pbr_map_match_mark_cmd
);
1164 install_element(PBRMAP_NODE
, &pbr_map_nexthop_group_cmd
);
1165 install_element(PBRMAP_NODE
, &no_pbr_map_nexthop_group_cmd
);
1166 install_element(PBRMAP_NODE
, &pbr_map_nexthop_cmd
);
1167 install_element(PBRMAP_NODE
, &no_pbr_map_nexthop_cmd
);
1168 install_element(PBRMAP_NODE
, &pbr_map_vrf_cmd
);
1169 install_element(PBRMAP_NODE
, &no_pbr_map_vrf_cmd
);
1170 install_element(VIEW_NODE
, &show_pbr_cmd
);
1171 install_element(VIEW_NODE
, &show_pbr_map_cmd
);
1172 install_element(VIEW_NODE
, &show_pbr_interface_cmd
);
1173 install_element(VIEW_NODE
, &show_pbr_nexthop_group_cmd
);