]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_vty.c
Merge pull request #10105 from ton31337/feature/rfc9072
[mirror_frr.git] / pbrd / pbr_vty.c
1 /*
2 * PBR - vty code
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
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
9 * later version.
10 *
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.
15 *
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
19 */
20 #include <zebra.h>
21
22 #include "vty.h"
23 #include "command.h"
24 #include "prefix.h"
25 #include "vrf.h"
26 #include "nexthop.h"
27 #include "nexthop_group.h"
28 #include "nexthop_group_private.h"
29 #include "log.h"
30 #include "json.h"
31 #include "debug.h"
32 #include "pbr.h"
33
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"
41 #endif
42
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"
47 "Sequence number\n")
48 {
49 const char *pbrm_name = argv[1]->arg;
50 uint32_t seqno = atoi(argv[3]->arg);
51 struct pbr_map_sequence *pbrms;
52
53 pbrms = pbrms_get(pbrm_name, seqno);
54 VTY_PUSH_CONTEXT(PBRMAP_NODE, pbrms);
55
56 return CMD_SUCCESS;
57 }
58
59 DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
60 NO_STR
61 "Delete pbr-map\n"
62 "The name of the PBR MAP\n"
63 "Sequence to delete from existing pbr-map entry\n"
64 "Sequence number\n")
65 {
66 const char *pbrm_name = argv[2]->arg;
67 uint32_t seqno = 0;
68 struct pbr_map *pbrm = pbrm_find(pbrm_name);
69 struct pbr_map_sequence *pbrms;
70 struct listnode *node, *next_node;
71
72 if (argc > 3)
73 seqno = atoi(argv[4]->arg);
74
75 if (!pbrm) {
76 vty_out(vty, "pbr-map %s not found\n", pbrm_name);
77 return CMD_SUCCESS;
78 }
79
80 for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, next_node, pbrms)) {
81 if (seqno && pbrms->seqno != seqno)
82 continue;
83
84 pbr_map_delete(pbrms);
85 }
86
87 return CMD_SUCCESS;
88 }
89
90 DEFPY(pbr_set_table_range,
91 pbr_set_table_range_cmd,
92 "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
93 PBR_STR
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")
98 {
99 /* upper bound is 2^32 - 2^10 */
100 int ret = CMD_WARNING;
101 const int minrange = 1000;
102
103 /* validate given bounds */
104 if (lb > ub)
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);
108 else {
109 ret = CMD_SUCCESS;
110 pbr_nht_set_tableid_range((uint32_t) lb, (uint32_t) ub);
111 }
112
113 return ret;
114 }
115
116 DEFPY(no_pbr_set_table_range, no_pbr_set_table_range_cmd,
117 "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
118 NO_STR
119 PBR_STR
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")
124 {
125 pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
126 PBR_NHT_DEFAULT_HIGH_TABLEID);
127 return CMD_SUCCESS;
128 }
129
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",
132 NO_STR
133 "Match the rest of the command\n"
134 "Choose the src ip or ipv6 prefix to use\n"
135 "v4 Prefix\n"
136 "v6 Prefix\n")
137 {
138 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
139
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;
143 }
144
145 pbrms->family = prefix->family;
146
147 if (!no) {
148 if (pbrms->src) {
149 if (prefix_same(pbrms->src, prefix))
150 return CMD_SUCCESS;
151 } else
152 pbrms->src = prefix_new();
153
154 prefix_copy(pbrms->src, prefix);
155 } else
156 prefix_free(&pbrms->src);
157
158 pbr_map_check(pbrms, true);
159
160 return CMD_SUCCESS;
161 }
162
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",
165 NO_STR
166 "Match the rest of the command\n"
167 "Choose the dst ip or ipv6 prefix to use\n"
168 "v4 Prefix\n"
169 "v6 Prefix\n")
170 {
171 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
172
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;
176 }
177
178 pbrms->family = prefix->family;
179
180 if (!no) {
181 if (pbrms->dst) {
182 if (prefix_same(pbrms->dst, prefix))
183 return CMD_SUCCESS;
184 } else
185 pbrms->dst = prefix_new();
186
187 prefix_copy(pbrms->dst, prefix);
188 } else
189 prefix_free(&pbrms->dst);
190
191 pbr_map_check(pbrms, true);
192
193 return CMD_SUCCESS;
194 }
195
196 DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd,
197 "[no] match ip-protocol [tcp|udp]$ip_proto",
198 NO_STR
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")
203 {
204 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
205 struct protoent *p;
206
207 if (!no) {
208 p = getprotobyname(ip_proto);
209 if (!p) {
210 vty_out(vty, "Unable to convert %s to proto id\n",
211 ip_proto);
212 return CMD_WARNING;
213 }
214
215 pbrms->ip_proto = p->p_proto;
216 } else
217 pbrms->ip_proto = 0;
218
219 return CMD_SUCCESS;
220 }
221
222 DEFPY(pbr_map_match_src_port, pbr_map_match_src_port_cmd,
223 "[no] match src-port (1-65535)$port",
224 NO_STR
225 "Match the rest of the command\n"
226 "Choose the source port to use\n"
227 "The Source Port\n")
228 {
229 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
230
231 if (!no) {
232 if (pbrms->src_prt == port)
233 return CMD_SUCCESS;
234 else
235 pbrms->src_prt = port;
236 } else
237 pbrms->src_prt = 0;
238
239 pbr_map_check(pbrms, true);
240
241 return CMD_SUCCESS;
242 }
243
244 DEFPY(pbr_map_match_dst_port, pbr_map_match_dst_port_cmd,
245 "[no] match dst-port (1-65535)$port",
246 NO_STR
247 "Match the rest of the command\n"
248 "Choose the destination port to use\n"
249 "The Destination Port\n")
250 {
251 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
252
253 if (!no) {
254 if (pbrms->dst_prt == port)
255 return CMD_SUCCESS;
256 else
257 pbrms->dst_prt = port;
258 } else
259 pbrms->dst_prt = 0;
260
261 pbr_map_check(pbrms, true);
262
263 return CMD_SUCCESS;
264 }
265
266 DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,
267 "[no] match dscp DSCP$dscp",
268 NO_STR
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")
272 {
273 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
274 char dscpname[100];
275 uint8_t rawDscp;
276
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]))
282 isANumber = false;
283
284 /* Lowercase the dscp enum (if needed) */
285 if (isupper(dscp[i]))
286 dscpname[i] = tolower(dscp[i]);
287 else
288 dscpname[i] = dscp[i];
289 }
290 dscpname[strlen(dscp)] = '\0';
291
292 if (isANumber) {
293 /* dscp passed is a regular number */
294 long dscpAsNum = strtol(dscp, NULL, 0);
295
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;
300 }
301 rawDscp = dscpAsNum;
302 } else {
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;
308 }
309 }
310
311 if (!no) {
312 if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == rawDscp)
313 return CMD_SUCCESS;
314
315 /* Set the DSCP bits of the DSField */
316 pbrms->dsfield =
317 (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2);
318 } else {
319 pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
320 }
321
322 pbr_map_check(pbrms, true);
323
324 return CMD_SUCCESS;
325 }
326
327 DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd,
328 "[no] match ecn (0-3)$ecn",
329 NO_STR
330 "Match the rest of the command\n"
331 "Match based on IP ECN field\n"
332 "Explicit Congestion Notification\n")
333 {
334 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
335
336 if (!no) {
337 if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)
338 return CMD_SUCCESS;
339
340 /* Set the ECN bits of the DSField */
341 pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
342 } else {
343 pbrms->dsfield &= ~PBR_DSFIELD_ECN;
344 }
345
346 pbr_map_check(pbrms, true);
347
348 return CMD_SUCCESS;
349 }
350
351 DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
352 "[no] match mark (1-4294967295)$mark",
353 NO_STR
354 "Match the rest of the command\n"
355 "Choose the mark value to use\n"
356 "mark\n")
357 {
358 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
359
360 #ifndef GNU_LINUX
361 vty_out(vty, "pbr marks are not supported on this platform");
362 return CMD_WARNING_CONFIG_FAILED;
363 #endif
364
365 if (!no) {
366 if (pbrms->mark)
367 if (pbrms->mark == (uint32_t)mark)
368 return CMD_SUCCESS;
369
370 pbrms->mark = (uint32_t)mark;
371 } else
372 pbrms->mark = 0;
373
374 pbr_map_check(pbrms, true);
375
376 return CMD_SUCCESS;
377 }
378
379 static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
380 {
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;
386 }
387 }
388
389 static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
390 {
391 if (pbrms->nhgrp_name)
392 pbr_map_delete_nexthops(pbrms);
393 }
394
395 static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
396 {
397 if (pbrms->nhg)
398 pbr_nht_delete_individual_nexthop(pbrms);
399 }
400
401 static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
402 {
403 pbrms_clear_set_vrf_config(pbrms);
404 pbrms_clear_set_nhg_config(pbrms);
405 pbrms_clear_set_nexthop_config(pbrms);
406
407 pbrms->nhs_installed = false;
408 }
409
410
411 DEFPY(pbr_map_action_queue_id, pbr_map_action_queue_id_cmd,
412 "[no] set queue-id <(1-65535)$queue_id>",
413 NO_STR
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")
417 {
418 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
419
420 if (!no)
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;
424
425 pbr_map_check(pbrms, true);
426
427 return CMD_SUCCESS;
428 }
429
430 DEFPY(pbr_map_action_pcp, pbr_map_action_pcp_cmd, "[no] set pcp <(0-7)$pcp>",
431 NO_STR
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")
435 {
436 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
437
438 if (!no)
439 pbrms->action_pcp = pcp;
440 else if (pcp == pbrms->action_pcp)
441 pbrms->action_pcp = 0;
442
443 pbr_map_check(pbrms, true);
444
445 return CMD_SUCCESS;
446 }
447
448 DEFPY(pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd,
449 "[no] set vlan <(1-4094)$vlan_id>",
450 NO_STR
451 "Set the rest of the command\n"
452 "Set action for VLAN tagging\n"
453 "A valid value in range 1..4094\n")
454 {
455 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
456
457 if (!no)
458 pbrms->action_vlan_id = vlan_id;
459 else if (pbrms->action_vlan_id == vlan_id)
460 pbrms->action_vlan_id = 0;
461
462 pbr_map_check(pbrms, true);
463
464 return CMD_SUCCESS;
465 }
466
467 DEFPY(pbr_map_action_strip_vlan, pbr_map_action_strip_vlan_cmd,
468 "[no] strip vlan",
469 NO_STR
470 "Strip the vlan tags from frame\n"
471 "Strip any inner vlan tag \n")
472 {
473 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
474
475 if (!no)
476 pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY;
477 else
478 pbrms->action_vlan_flags = 0;
479
480 pbr_map_check(pbrms, true);
481
482 return CMD_SUCCESS;
483 }
484
485
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")
491 {
492 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
493 struct nexthop_group_cmd *nhgc;
494
495 nhgc = nhgc_find(name);
496 if (!nhgc) {
497 vty_out(vty, "Specified nexthop-group %s does not exist\n",
498 name);
499 vty_out(vty,
500 "PBR-MAP will not be applied until it is created\n");
501 }
502
503 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
504 return CMD_SUCCESS;
505
506 /* This is new/replacement config */
507 pbrms_clear_set_config(pbrms);
508
509 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
510 pbr_map_check(pbrms, true);
511
512 return CMD_SUCCESS;
513 }
514
515 DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
516 "no set nexthop-group [NHGNAME$name]",
517 NO_STR
518 "Set for the PBR-MAP\n"
519 "nexthop-group to use\n"
520 "The name of the nexthop-group\n")
521 {
522 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
523
524 pbrms_clear_set_config(pbrms);
525
526 return CMD_SUCCESS;
527 }
528
529 DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
530 "set nexthop\
531 <\
532 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
533 |INTERFACE$intf\
534 >\
535 [nexthop-vrf NAME$vrf_name]",
536 "Set for the PBR-MAP\n"
537 "Specify one of the nexthops in this map\n"
538 "v4 Address\n"
539 "v6 Address\n"
540 "Interface to use\n"
541 "Interface to use\n"
542 "If the nexthop is in a different vrf tell us\n"
543 "The nexthop-vrf Name\n")
544 {
545 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
546 struct vrf *vrf;
547 struct nexthop nhop;
548 struct nexthop *nh = NULL;
549
550 if (vrf_name)
551 vrf = vrf_lookup_by_name(vrf_name);
552 else
553 vrf = vrf_lookup_by_id(VRF_DEFAULT);
554
555 if (!vrf) {
556 vty_out(vty, "Specified VRF: %s is non-existent\n", vrf_name);
557 return CMD_WARNING_CONFIG_FAILED;
558 }
559
560 memset(&nhop, 0, sizeof(nhop));
561 nhop.vrf_id = vrf->vrf_id;
562
563 if (intf) {
564 struct interface *ifp = NULL;
565 struct interface *ifptmp;
566 struct vrf *vrftmp;
567 int count = 0;
568
569 if (vrf_is_backend_netns() && vrf_name) {
570 ifp = if_lookup_by_name_vrf(intf, vrf);
571 } else {
572 RB_FOREACH (vrftmp, vrf_name_head, &vrfs_by_name) {
573 ifptmp = if_lookup_by_name_vrf(intf, vrftmp);
574 if (ifptmp) {
575 ifp = ifptmp;
576 count++;
577 if (!vrf_is_backend_netns())
578 break;
579 }
580 }
581 }
582
583 if (!ifp) {
584 vty_out(vty, "Specified Intf %s does not exist\n",
585 intf);
586 return CMD_WARNING_CONFIG_FAILED;
587 }
588 if (count > 1) {
589 vty_out(vty,
590 "Specified Intf %s exists in multiple VRFs\n",
591 intf);
592 vty_out(vty, "You must specify the nexthop-vrf\n");
593 return CMD_WARNING_CONFIG_FAILED;
594 }
595 if (ifp->vrf->vrf_id != vrf->vrf_id)
596 vty_out(vty,
597 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
598 ifp->name, vrf->name, ifp->vrf->name);
599 nhop.ifindex = ifp->ifindex;
600 nhop.vrf_id = ifp->vrf->vrf_id;
601 }
602
603 if (addr) {
604 if (addr->sa.sa_family == AF_INET) {
605 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
606 if (intf)
607 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
608 else
609 nhop.type = NEXTHOP_TYPE_IPV4;
610 } else {
611 nhop.gate.ipv6 = addr->sin6.sin6_addr;
612 if (intf)
613 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
614 else {
615 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
616 vty_out(vty,
617 "Specified a v6 LL with no interface, rejecting\n");
618 return CMD_WARNING_CONFIG_FAILED;
619 }
620 nhop.type = NEXTHOP_TYPE_IPV6;
621 }
622 }
623 } else
624 nhop.type = NEXTHOP_TYPE_IFINDEX;
625
626 if (pbrms->nhg)
627 nh = nexthop_exists(pbrms->nhg, &nhop);
628
629 if (nh) /* Same config re-entered */
630 goto done;
631
632 /* This is new/replacement config */
633 pbrms_clear_set_config(pbrms);
634
635 pbr_nht_add_individual_nexthop(pbrms, &nhop);
636
637 pbr_map_check(pbrms, true);
638
639 done:
640 if (nhop.type == NEXTHOP_TYPE_IFINDEX
641 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
642 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
643 struct interface *ifp;
644
645 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
646 if (ifp)
647 pbr_nht_nexthop_interface_update(ifp);
648 }
649
650 return CMD_SUCCESS;
651 }
652
653 DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
654 "no set nexthop\
655 [<\
656 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
657 |INTERFACE$intf\
658 >\
659 [nexthop-vrf NAME$vrf_name]]",
660 NO_STR
661 "Set for the PBR-MAP\n"
662 "Specify one of the nexthops in this map\n"
663 "v4 Address\n"
664 "v6 Address\n"
665 "Interface to use\n"
666 "Interface to use\n"
667 "If the nexthop is in a different vrf tell us\n"
668 "The nexthop-vrf Name\n")
669 {
670 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
671
672 pbrms_clear_set_config(pbrms);
673
674 return CMD_SUCCESS;
675 }
676
677 DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
678 "set vrf <NAME$vrf_name|unchanged>",
679 "Set for the PBR-MAP\n"
680 "Specify the VRF for this map\n"
681 "The VRF Name\n"
682 "Use the interface's VRF for lookup\n")
683 {
684 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
685
686 /*
687 * If an equivalent set vrf * exists, just return success.
688 */
689 if (vrf_name && pbrms->vrf_lookup
690 && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0)
691 return CMD_SUCCESS;
692 else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */
693 return CMD_SUCCESS;
694
695 if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) {
696 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
697 return CMD_WARNING_CONFIG_FAILED;
698 }
699
700 /* This is new/replacement config */
701 pbrms_clear_set_config(pbrms);
702
703 if (vrf_name) {
704 pbrms->vrf_lookup = true;
705 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
706 } else
707 pbrms->vrf_unchanged = true;
708
709 pbr_map_check(pbrms, true);
710
711 return CMD_SUCCESS;
712 }
713
714 DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
715 "no set vrf [<NAME$vrf_name|unchanged>]",
716 NO_STR
717 "Set for the PBR-MAP\n"
718 "Specify the VRF for this map\n"
719 "The VRF Name\n"
720 "Use the interface's VRF for lookup\n")
721 {
722 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
723
724 pbrms_clear_set_config(pbrms);
725
726 return CMD_SUCCESS;
727 }
728
729 DEFPY (pbr_policy,
730 pbr_policy_cmd,
731 "[no] pbr-policy PBRMAP$mapname",
732 NO_STR
733 "Policy to use\n"
734 "Name of the pbr-map to apply\n")
735 {
736 VTY_DECLVAR_CONTEXT(interface, ifp);
737 struct pbr_map *pbrm, *old_pbrm;
738 struct pbr_interface *pbr_ifp = ifp->info;
739
740 old_pbrm = NULL;
741 pbrm = pbrm_find(mapname);
742
743 if (!pbr_ifp) {
744 /* we don't want one and we don't have one, so... */
745 if (no)
746 return CMD_SUCCESS;
747
748 /* Some one could have fat fingered the interface name */
749 pbr_ifp = pbr_if_new(ifp);
750 }
751
752 if (no) {
753 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
754 pbr_ifp->mapname[0] = '\0';
755 if (pbrm)
756 pbr_map_interface_delete(pbrm, ifp);
757 }
758 } else {
759 if (strcmp(pbr_ifp->mapname, "") != 0) {
760 old_pbrm = pbrm_find(pbr_ifp->mapname);
761
762 /*
763 * So if we have an old pbrm we should only
764 * delete it if we are actually deleting and
765 * moving to a new pbrm
766 */
767 if (old_pbrm && old_pbrm != pbrm)
768 pbr_map_interface_delete(old_pbrm, ifp);
769 }
770 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
771 "%s", mapname);
772
773 /*
774 * So only reinstall if the old_pbrm and this pbrm are
775 * different.
776 */
777 if (pbrm && pbrm != old_pbrm)
778 pbr_map_add_interface(pbrm, ifp);
779 }
780
781 return CMD_SUCCESS;
782 }
783
784 DEFPY (show_pbr,
785 show_pbr_cmd,
786 "show pbr",
787 SHOW_STR
788 PBR_STR)
789 {
790 pbr_nht_write_table_range(vty);
791 pbr_nht_write_rule_range(vty);
792
793 return CMD_SUCCESS;
794 }
795
796 static void
797 pbrms_nexthop_group_write_individual_nexthop(
798 struct vty *vty, const struct pbr_map_sequence *pbrms)
799 {
800 struct pbr_nexthop_group_cache find;
801 struct pbr_nexthop_group_cache *pnhgc;
802 struct pbr_nexthop_cache lookup;
803 struct pbr_nexthop_cache *pnhc;
804
805 memset(&find, 0, sizeof(find));
806 strlcpy(find.name, pbrms->internal_nhg_name, sizeof(find.name));
807
808 pnhgc = hash_lookup(pbr_nhg_hash, &find);
809 assert(pnhgc);
810
811 lookup.nexthop = *pbrms->nhg->nexthop;
812 pnhc = hash_lookup(pnhgc->nhh, &lookup);
813
814 nexthop_group_write_nexthop_simple(
815 vty, pbrms->nhg->nexthop,
816 pnhc->nexthop.ifindex != 0 ? pnhc->intf_name : NULL);
817 if (pnhc->nexthop.vrf_id != VRF_DEFAULT)
818 vty_out(vty, " nexthop-vrf %s", pnhc->vrf_name);
819
820 vty_out(vty, "\n");
821 }
822
823 static void vty_show_pbrms(struct vty *vty,
824 const struct pbr_map_sequence *pbrms, bool detail)
825 {
826 char rbuf[64];
827
828 if (pbrms->reason)
829 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
830
831 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
832
833 if (detail)
834 vty_out(vty, " Installed: %" PRIu64 "(%u) Reason: %s\n",
835 pbrms->installed, pbrms->unique,
836 pbrms->reason ? rbuf : "Valid");
837 else
838 vty_out(vty, " Installed: %s Reason: %s\n",
839 pbrms->installed ? "yes" : "no",
840 pbrms->reason ? rbuf : "Valid");
841
842 if (pbrms->ip_proto) {
843 struct protoent *p;
844
845 p = getprotobynumber(pbrms->ip_proto);
846 vty_out(vty, " IP Protocol Match: %s\n", p->p_name);
847 }
848
849 if (pbrms->src)
850 vty_out(vty, " SRC Match: %pFX\n", pbrms->src);
851 if (pbrms->dst)
852 vty_out(vty, " DST Match: %pFX\n", pbrms->dst);
853 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
854 vty_out(vty, " DSCP Match: %u\n",
855 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
856 if (pbrms->dsfield & PBR_DSFIELD_ECN)
857 vty_out(vty, " ECN Match: %u\n",
858 pbrms->dsfield & PBR_DSFIELD_ECN);
859 if (pbrms->mark)
860 vty_out(vty, " MARK Match: %u\n", pbrms->mark);
861
862 if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
863 vty_out(vty, " Set Queue ID %u\n",
864 pbrms->action_queue_id);
865
866 if (pbrms->action_vlan_id != 0)
867 vty_out(vty, " Set VLAN ID %u\n", pbrms->action_vlan_id);
868 if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
869 vty_out(vty, " Strip VLAN ID\n");
870 if (pbrms->action_pcp)
871 vty_out(vty, " Set PCP %u\n", pbrms->action_pcp);
872
873
874 if (pbrms->nhgrp_name) {
875 vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
876
877 if (detail)
878 vty_out(vty,
879 " Installed: %u(%d) Tableid: %d\n",
880 pbrms->nhs_installed,
881 pbr_nht_get_installed(pbrms->nhgrp_name),
882 pbr_nht_get_table(pbrms->nhgrp_name));
883 else
884 vty_out(vty, " Installed: %s Tableid: %d\n",
885 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
886 : "no",
887 pbr_nht_get_table(pbrms->nhgrp_name));
888
889 } else if (pbrms->nhg) {
890 vty_out(vty, " ");
891 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
892 if (detail)
893 vty_out(vty,
894 " Installed: %u(%d) Tableid: %d\n",
895 pbrms->nhs_installed,
896 pbr_nht_get_installed(pbrms->internal_nhg_name),
897 pbr_nht_get_table(pbrms->internal_nhg_name));
898 else
899 vty_out(vty, " Installed: %s Tableid: %d\n",
900 pbr_nht_get_installed(pbrms->internal_nhg_name)
901 ? "yes"
902 : "no",
903 pbr_nht_get_table(pbrms->internal_nhg_name));
904
905 } else if (pbrms->vrf_unchanged) {
906 vty_out(vty, " VRF Unchanged (use interface vrf)\n");
907 } else if (pbrms->vrf_lookup) {
908 vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name);
909 } else {
910 vty_out(vty, " Nexthop-Group: Unknown Installed: no\n");
911 }
912 }
913
914 static void vty_json_pbrms(json_object *j, struct vty *vty,
915 const struct pbr_map_sequence *pbrms)
916 {
917 json_object *jpbrm, *nexthop_group;
918 char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
919 : pbrms->internal_nhg_name;
920 char rbuf[64];
921
922 jpbrm = json_object_new_object();
923
924 json_object_int_add(jpbrm, "id", pbrms->unique);
925
926 if (pbrms->reason)
927 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
928
929 json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
930 json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
931 json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
932 json_object_boolean_add(jpbrm, "installed",
933 pbr_nht_get_installed(nhg_name));
934 json_object_string_add(jpbrm, "installedReason",
935 pbrms->reason ? rbuf : "Valid");
936
937 if (nhg_name) {
938 nexthop_group = json_object_new_object();
939
940 json_object_int_add(nexthop_group, "tableId",
941 pbr_nht_get_table(nhg_name));
942 json_object_string_add(nexthop_group, "name", nhg_name);
943 json_object_boolean_add(nexthop_group, "installed",
944 pbr_nht_get_installed(nhg_name));
945 json_object_int_add(nexthop_group, "installedInternally",
946 pbrms->nhs_installed);
947
948 json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
949 }
950
951 if (pbrms->vrf_lookup)
952 json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
953
954 if (pbrms->src)
955 json_object_string_addf(jpbrm, "matchSrc", "%pFX", pbrms->src);
956 if (pbrms->dst)
957 json_object_string_addf(jpbrm, "matchDst", "%pFX", pbrms->dst);
958 if (pbrms->mark)
959 json_object_int_add(jpbrm, "matchMark", pbrms->mark);
960 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
961 json_object_int_add(jpbrm, "matchDscp",
962 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
963 if (pbrms->dsfield & PBR_DSFIELD_ECN)
964 json_object_int_add(jpbrm, "matchEcn",
965 pbrms->dsfield & PBR_DSFIELD_ECN);
966
967 json_object_array_add(j, jpbrm);
968 }
969
970 static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
971 bool detail)
972 {
973 struct pbr_map_sequence *pbrms;
974 struct listnode *node;
975
976 vty_out(vty, " pbr-map %s valid: %s\n", pbrm->name,
977 pbrm->valid ? "yes" : "no");
978
979 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
980 vty_show_pbrms(vty, pbrms, detail);
981 }
982
983 static void vty_json_pbr_map(json_object *j, struct vty *vty,
984 const struct pbr_map *pbrm)
985 {
986 struct pbr_map_sequence *pbrms;
987 struct listnode *node;
988 json_object *jpbrms;
989
990 json_object_string_add(j, "name", pbrm->name);
991 json_object_boolean_add(j, "valid", pbrm->valid);
992
993 jpbrms = json_object_new_array();
994
995 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
996 vty_json_pbrms(jpbrms, vty, pbrms);
997
998 json_object_object_add(j, "policies", jpbrms);
999 }
1000
1001 DEFPY (show_pbr_map,
1002 show_pbr_map_cmd,
1003 "show pbr map [NAME$name] [detail$detail|json$json]",
1004 SHOW_STR
1005 PBR_STR
1006 "PBR Map\n"
1007 "PBR Map Name\n"
1008 "Detailed information\n"
1009 JSON_STR)
1010 {
1011 struct pbr_map *pbrm;
1012 json_object *j = NULL;
1013
1014 if (json)
1015 j = json_object_new_array();
1016
1017 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
1018 json_object *this_map = NULL;
1019 if (name && strcmp(name, pbrm->name) != 0)
1020 continue;
1021
1022 if (j)
1023 this_map = json_object_new_object();
1024
1025 if (this_map) {
1026 vty_json_pbr_map(this_map, vty, pbrm);
1027
1028 json_object_array_add(j, this_map);
1029 continue;
1030 }
1031
1032 vty_show_pbr_map(vty, pbrm, detail);
1033 }
1034
1035 if (j)
1036 vty_json(vty, j);
1037
1038 return CMD_SUCCESS;
1039 }
1040
1041 DEFPY(show_pbr_nexthop_group,
1042 show_pbr_nexthop_group_cmd,
1043 "show pbr nexthop-groups [WORD$word] [json$json]",
1044 SHOW_STR
1045 PBR_STR
1046 "Nexthop Groups\n"
1047 "Optional Name of the nexthop group\n"
1048 JSON_STR)
1049 {
1050 json_object *j = NULL;
1051
1052 if (json)
1053 j = json_object_new_array();
1054
1055 if (j) {
1056 pbr_nht_json_nexthop_group(j, word);
1057
1058 vty_json(vty, j);
1059 } else
1060 pbr_nht_show_nexthop_group(vty, word);
1061
1062
1063 return CMD_SUCCESS;
1064 }
1065
1066 DEFPY (show_pbr_interface,
1067 show_pbr_interface_cmd,
1068 "show pbr interface [NAME$name] [json$json]",
1069 SHOW_STR
1070 PBR_STR
1071 "PBR Interface\n"
1072 "PBR Interface Name\n"
1073 JSON_STR)
1074 {
1075 struct interface *ifp;
1076 struct vrf *vrf;
1077 struct pbr_interface *pbr_ifp;
1078 json_object *j = NULL;
1079
1080 if (json)
1081 j = json_object_new_array();
1082
1083 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
1084 FOR_ALL_INTERFACES(vrf, ifp) {
1085 struct pbr_map *pbrm;
1086 json_object *this_iface = NULL;
1087
1088 if (j)
1089 this_iface = json_object_new_object();
1090
1091 if (!ifp->info) {
1092 json_object_free(this_iface);
1093 continue;
1094 }
1095
1096 if (name && strcmp(ifp->name, name) != 0) {
1097 json_object_free(this_iface);
1098 continue;
1099 }
1100
1101 pbr_ifp = ifp->info;
1102
1103 if (strcmp(pbr_ifp->mapname, "") == 0) {
1104 json_object_free(this_iface);
1105 continue;
1106 }
1107
1108 pbrm = pbrm_find(pbr_ifp->mapname);
1109
1110 if (this_iface) {
1111 json_object_string_add(this_iface, "name",
1112 ifp->name);
1113 json_object_int_add(this_iface, "index",
1114 ifp->ifindex);
1115 json_object_string_add(this_iface, "policy",
1116 pbr_ifp->mapname);
1117 json_object_boolean_add(this_iface, "valid",
1118 pbrm);
1119
1120 json_object_array_add(j, this_iface);
1121 continue;
1122 }
1123
1124 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
1125 ifp->ifindex, pbr_ifp->mapname);
1126 if (!pbrm)
1127 vty_out(vty, " (map doesn't exist)");
1128 vty_out(vty, "\n");
1129 }
1130 }
1131
1132 if (j)
1133 vty_json(vty, j);
1134
1135 return CMD_SUCCESS;
1136 }
1137
1138 /* PBR debugging CLI ------------------------------------------------------- */
1139
1140 static struct cmd_node debug_node = {
1141 .name = "debug",
1142 .node = DEBUG_NODE,
1143 .prompt = "",
1144 .config_write = pbr_debug_config_write,
1145 };
1146
1147 DEFPY(debug_pbr,
1148 debug_pbr_cmd,
1149 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
1150 NO_STR
1151 DEBUG_STR
1152 PBR_STR
1153 "Policy maps\n"
1154 "PBRD <-> Zebra communications\n"
1155 "Nexthop tracking\n"
1156 "Events\n")
1157 {
1158 uint32_t mode = DEBUG_NODE2MODE(vty->node);
1159
1160 if (map)
1161 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
1162 if (zebra)
1163 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
1164 if (nht)
1165 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
1166 if (events)
1167 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
1168
1169 /* no specific debug --> act on all of them */
1170 if (strmatch(argv[argc - 1]->text, "pbr"))
1171 pbr_debug_set_all(mode, !no);
1172
1173 return CMD_SUCCESS;
1174 }
1175
1176 DEFUN_NOSH(show_debugging_pbr,
1177 show_debugging_pbr_cmd,
1178 "show debugging [pbr]",
1179 SHOW_STR
1180 DEBUG_STR
1181 PBR_STR)
1182 {
1183 vty_out(vty, "PBR debugging status:\n");
1184
1185 pbr_debug_config_write_helper(vty, false);
1186
1187 return CMD_SUCCESS;
1188 }
1189
1190 /* ------------------------------------------------------------------------- */
1191
1192
1193 static int pbr_interface_config_write(struct vty *vty)
1194 {
1195 struct interface *ifp;
1196 struct vrf *vrf;
1197
1198 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1199 FOR_ALL_INTERFACES (vrf, ifp) {
1200 if (vrf->vrf_id == VRF_DEFAULT)
1201 vty_frame(vty, "interface %s\n", ifp->name);
1202 else
1203 vty_frame(vty, "interface %s vrf %s\n",
1204 ifp->name, vrf->name);
1205
1206 if (ifp->desc)
1207 vty_out(vty, " description %s\n", ifp->desc);
1208
1209 pbr_map_write_interfaces(vty, ifp);
1210
1211 vty_endframe(vty, "exit\n!\n");
1212 }
1213 }
1214
1215 return 1;
1216 }
1217
1218 static int pbr_vty_map_config_write(struct vty *vty);
1219 /* PBR map node structure. */
1220 static struct cmd_node pbr_map_node = {
1221 .name = "pbr-map",
1222 .node = PBRMAP_NODE,
1223 .parent_node = CONFIG_NODE,
1224 .prompt = "%s(config-pbr-map)# ",
1225 .config_write = pbr_vty_map_config_write,
1226 };
1227
1228 static int pbr_vty_map_config_write_sequence(struct vty *vty,
1229 struct pbr_map *pbrm,
1230 struct pbr_map_sequence *pbrms)
1231 {
1232 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
1233
1234 if (pbrms->src)
1235 vty_out(vty, " match src-ip %pFX\n", pbrms->src);
1236
1237 if (pbrms->dst)
1238 vty_out(vty, " match dst-ip %pFX\n", pbrms->dst);
1239
1240 if (pbrms->src_prt)
1241 vty_out(vty, " match src-port %u\n", pbrms->src_prt);
1242 if (pbrms->dst_prt)
1243 vty_out(vty, " match dst-port %u\n", pbrms->dst_prt);
1244
1245 if (pbrms->ip_proto) {
1246 struct protoent *p;
1247
1248 p = getprotobynumber(pbrms->ip_proto);
1249 vty_out(vty, " match ip-protocol %s\n", p->p_name);
1250 }
1251
1252 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
1253 vty_out(vty, " match dscp %u\n",
1254 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
1255
1256 if (pbrms->dsfield & PBR_DSFIELD_ECN)
1257 vty_out(vty, " match ecn %u\n",
1258 pbrms->dsfield & PBR_DSFIELD_ECN);
1259
1260 if (pbrms->mark)
1261 vty_out(vty, " match mark %u\n", pbrms->mark);
1262
1263
1264 if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
1265 vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id);
1266
1267 if (pbrms->action_pcp)
1268 vty_out(vty, " set pcp %d\n", pbrms->action_pcp);
1269
1270 if (pbrms->action_vlan_id)
1271 vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id);
1272
1273 if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
1274 vty_out(vty, " strip vlan any\n");
1275
1276 if (pbrms->vrf_unchanged)
1277 vty_out(vty, " set vrf unchanged\n");
1278
1279 if (pbrms->vrf_lookup)
1280 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
1281
1282 if (pbrms->nhgrp_name)
1283 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
1284
1285 if (pbrms->nhg) {
1286 vty_out(vty, " set ");
1287 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
1288 }
1289
1290 vty_out(vty, "exit\n");
1291 vty_out(vty, "!\n");
1292 return 1;
1293 }
1294
1295 static int pbr_vty_map_config_write(struct vty *vty)
1296 {
1297 struct pbr_map *pbrm;
1298
1299 pbr_nht_write_table_range(vty);
1300 pbr_nht_write_rule_range(vty);
1301
1302 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
1303 struct pbr_map_sequence *pbrms;
1304 struct listnode *node;
1305
1306 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
1307 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
1308 }
1309
1310 return 1;
1311 }
1312
1313 static void pbr_map_completer(vector comps, struct cmd_token *token)
1314 {
1315 struct pbr_map *pbrm;
1316
1317 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
1318 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
1319 }
1320
1321 static const struct cmd_variable_handler pbr_map_name[] = {
1322 {
1323 .tokenname = "PBRMAP", .completions = pbr_map_completer,
1324 },
1325 {
1326 .completions = NULL
1327 }
1328 };
1329
1330 extern struct zebra_privs_t pbr_privs;
1331
1332 void pbr_vty_init(void)
1333 {
1334 cmd_variable_handler_register(pbr_map_name);
1335
1336 vrf_cmd_init(NULL);
1337
1338 if_cmd_init(pbr_interface_config_write);
1339
1340 install_node(&pbr_map_node);
1341
1342 /* debug */
1343 install_node(&debug_node);
1344 install_element(ENABLE_NODE, &debug_pbr_cmd);
1345 install_element(CONFIG_NODE, &debug_pbr_cmd);
1346 install_element(ENABLE_NODE, &show_debugging_pbr_cmd);
1347
1348 install_default(PBRMAP_NODE);
1349
1350 install_element(CONFIG_NODE, &pbr_map_cmd);
1351 install_element(CONFIG_NODE, &no_pbr_map_cmd);
1352 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
1353 install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);
1354 install_element(INTERFACE_NODE, &pbr_policy_cmd);
1355 install_element(PBRMAP_NODE, &pbr_map_match_ip_proto_cmd);
1356 install_element(PBRMAP_NODE, &pbr_map_match_src_port_cmd);
1357 install_element(PBRMAP_NODE, &pbr_map_match_dst_port_cmd);
1358 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
1359 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
1360 install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
1361 install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
1362 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
1363 install_element(PBRMAP_NODE, &pbr_map_action_queue_id_cmd);
1364 install_element(PBRMAP_NODE, &pbr_map_action_strip_vlan_cmd);
1365 install_element(PBRMAP_NODE, &pbr_map_action_vlan_id_cmd);
1366 install_element(PBRMAP_NODE, &pbr_map_action_pcp_cmd);
1367 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
1368 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
1369 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
1370 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_cmd);
1371 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
1372 install_element(PBRMAP_NODE, &no_pbr_map_vrf_cmd);
1373 install_element(VIEW_NODE, &show_pbr_cmd);
1374 install_element(VIEW_NODE, &show_pbr_map_cmd);
1375 install_element(VIEW_NODE, &show_pbr_interface_cmd);
1376 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
1377 }