]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_vty.c
Merge pull request #10417 from Orange-OpenSource/TE
[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 pbr_nht_set_seq_nhg(pbrms, name);
510
511 pbr_map_check(pbrms, true);
512
513 return CMD_SUCCESS;
514 }
515
516 DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
517 "no set nexthop-group [NHGNAME$name]",
518 NO_STR
519 "Set for the PBR-MAP\n"
520 "nexthop-group to use\n"
521 "The name of the nexthop-group\n")
522 {
523 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
524
525 pbrms_clear_set_config(pbrms);
526
527 return CMD_SUCCESS;
528 }
529
530 DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
531 "set nexthop\
532 <\
533 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
534 |INTERFACE$intf\
535 >\
536 [nexthop-vrf NAME$vrf_name]",
537 "Set for the PBR-MAP\n"
538 "Specify one of the nexthops in this map\n"
539 "v4 Address\n"
540 "v6 Address\n"
541 "Interface to use\n"
542 "Interface to use\n"
543 "If the nexthop is in a different vrf tell us\n"
544 "The nexthop-vrf Name\n")
545 {
546 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
547 struct vrf *vrf;
548 struct nexthop nhop;
549 struct nexthop *nh = NULL;
550
551 if (vrf_name)
552 vrf = vrf_lookup_by_name(vrf_name);
553 else
554 vrf = vrf_lookup_by_id(VRF_DEFAULT);
555
556 if (!vrf) {
557 vty_out(vty, "Specified VRF: %s is non-existent\n", vrf_name);
558 return CMD_WARNING_CONFIG_FAILED;
559 }
560
561 memset(&nhop, 0, sizeof(nhop));
562 nhop.vrf_id = vrf->vrf_id;
563
564 if (intf) {
565 struct interface *ifp = NULL;
566 struct interface *ifptmp;
567 struct vrf *vrftmp;
568 int count = 0;
569
570 if (vrf_is_backend_netns() && vrf_name) {
571 ifp = if_lookup_by_name_vrf(intf, vrf);
572 } else {
573 RB_FOREACH (vrftmp, vrf_name_head, &vrfs_by_name) {
574 ifptmp = if_lookup_by_name_vrf(intf, vrftmp);
575 if (ifptmp) {
576 ifp = ifptmp;
577 count++;
578 if (!vrf_is_backend_netns())
579 break;
580 }
581 }
582 }
583
584 if (!ifp) {
585 vty_out(vty, "Specified Intf %s does not exist\n",
586 intf);
587 return CMD_WARNING_CONFIG_FAILED;
588 }
589 if (count > 1) {
590 vty_out(vty,
591 "Specified Intf %s exists in multiple VRFs\n",
592 intf);
593 vty_out(vty, "You must specify the nexthop-vrf\n");
594 return CMD_WARNING_CONFIG_FAILED;
595 }
596 if (ifp->vrf->vrf_id != vrf->vrf_id)
597 vty_out(vty,
598 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
599 ifp->name, vrf->name, ifp->vrf->name);
600 nhop.ifindex = ifp->ifindex;
601 nhop.vrf_id = ifp->vrf->vrf_id;
602 }
603
604 if (addr) {
605 if (addr->sa.sa_family == AF_INET) {
606 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
607 if (intf)
608 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
609 else
610 nhop.type = NEXTHOP_TYPE_IPV4;
611 } else {
612 nhop.gate.ipv6 = addr->sin6.sin6_addr;
613 if (intf)
614 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
615 else {
616 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
617 vty_out(vty,
618 "Specified a v6 LL with no interface, rejecting\n");
619 return CMD_WARNING_CONFIG_FAILED;
620 }
621 nhop.type = NEXTHOP_TYPE_IPV6;
622 }
623 }
624 } else
625 nhop.type = NEXTHOP_TYPE_IFINDEX;
626
627 if (pbrms->nhg)
628 nh = nexthop_exists(pbrms->nhg, &nhop);
629
630 if (nh) /* Same config re-entered */
631 goto done;
632
633 /* This is new/replacement config */
634 pbrms_clear_set_config(pbrms);
635
636 pbr_nht_add_individual_nexthop(pbrms, &nhop);
637
638 pbr_map_check(pbrms, true);
639
640 done:
641 if (nhop.type == NEXTHOP_TYPE_IFINDEX
642 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
643 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
644 struct interface *ifp;
645
646 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
647 if (ifp)
648 pbr_nht_nexthop_interface_update(ifp);
649 }
650
651 return CMD_SUCCESS;
652 }
653
654 DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
655 "no set nexthop\
656 [<\
657 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
658 |INTERFACE$intf\
659 >\
660 [nexthop-vrf NAME$vrf_name]]",
661 NO_STR
662 "Set for the PBR-MAP\n"
663 "Specify one of the nexthops in this map\n"
664 "v4 Address\n"
665 "v6 Address\n"
666 "Interface to use\n"
667 "Interface to use\n"
668 "If the nexthop is in a different vrf tell us\n"
669 "The nexthop-vrf Name\n")
670 {
671 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
672
673 pbrms_clear_set_config(pbrms);
674
675 return CMD_SUCCESS;
676 }
677
678 DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
679 "set vrf <NAME$vrf_name|unchanged>",
680 "Set for the PBR-MAP\n"
681 "Specify the VRF for this map\n"
682 "The VRF Name\n"
683 "Use the interface's VRF for lookup\n")
684 {
685 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
686
687 /*
688 * If an equivalent set vrf * exists, just return success.
689 */
690 if (vrf_name && pbrms->vrf_lookup
691 && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0)
692 return CMD_SUCCESS;
693 else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */
694 return CMD_SUCCESS;
695
696 if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) {
697 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
698 return CMD_WARNING_CONFIG_FAILED;
699 }
700
701 /* This is new/replacement config */
702 pbrms_clear_set_config(pbrms);
703
704 if (vrf_name) {
705 pbrms->vrf_lookup = true;
706 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
707 } else
708 pbrms->vrf_unchanged = true;
709
710 pbr_map_check(pbrms, true);
711
712 return CMD_SUCCESS;
713 }
714
715 DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
716 "no set vrf [<NAME$vrf_name|unchanged>]",
717 NO_STR
718 "Set for the PBR-MAP\n"
719 "Specify the VRF for this map\n"
720 "The VRF Name\n"
721 "Use the interface's VRF for lookup\n")
722 {
723 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
724
725 pbrms_clear_set_config(pbrms);
726
727 return CMD_SUCCESS;
728 }
729
730 DEFPY (pbr_policy,
731 pbr_policy_cmd,
732 "[no] pbr-policy PBRMAP$mapname",
733 NO_STR
734 "Policy to use\n"
735 "Name of the pbr-map to apply\n")
736 {
737 VTY_DECLVAR_CONTEXT(interface, ifp);
738 struct pbr_map *pbrm, *old_pbrm;
739 struct pbr_interface *pbr_ifp = ifp->info;
740
741 old_pbrm = NULL;
742 pbrm = pbrm_find(mapname);
743
744 if (!pbr_ifp) {
745 /* we don't want one and we don't have one, so... */
746 if (no)
747 return CMD_SUCCESS;
748
749 /* Some one could have fat fingered the interface name */
750 pbr_ifp = pbr_if_new(ifp);
751 }
752
753 if (no) {
754 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
755 pbr_ifp->mapname[0] = '\0';
756 if (pbrm)
757 pbr_map_interface_delete(pbrm, ifp);
758 }
759 } else {
760 if (strcmp(pbr_ifp->mapname, "") != 0) {
761 old_pbrm = pbrm_find(pbr_ifp->mapname);
762
763 /*
764 * So if we have an old pbrm we should only
765 * delete it if we are actually deleting and
766 * moving to a new pbrm
767 */
768 if (old_pbrm && old_pbrm != pbrm)
769 pbr_map_interface_delete(old_pbrm, ifp);
770 }
771 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
772 "%s", mapname);
773
774 /*
775 * So only reinstall if the old_pbrm and this pbrm are
776 * different.
777 */
778 if (pbrm && pbrm != old_pbrm)
779 pbr_map_add_interface(pbrm, ifp);
780 }
781
782 return CMD_SUCCESS;
783 }
784
785 DEFPY (show_pbr,
786 show_pbr_cmd,
787 "show pbr",
788 SHOW_STR
789 PBR_STR)
790 {
791 pbr_nht_write_table_range(vty);
792 pbr_nht_write_rule_range(vty);
793
794 return CMD_SUCCESS;
795 }
796
797 static void
798 pbrms_nexthop_group_write_individual_nexthop(
799 struct vty *vty, const struct pbr_map_sequence *pbrms)
800 {
801 struct pbr_nexthop_group_cache find;
802 struct pbr_nexthop_group_cache *pnhgc;
803 struct pbr_nexthop_cache lookup;
804 struct pbr_nexthop_cache *pnhc;
805
806 memset(&find, 0, sizeof(find));
807 strlcpy(find.name, pbrms->internal_nhg_name, sizeof(find.name));
808
809 pnhgc = hash_lookup(pbr_nhg_hash, &find);
810 assert(pnhgc);
811
812 lookup.nexthop = *pbrms->nhg->nexthop;
813 pnhc = hash_lookup(pnhgc->nhh, &lookup);
814
815 nexthop_group_write_nexthop_simple(
816 vty, pbrms->nhg->nexthop,
817 pnhc->nexthop.ifindex != 0 ? pnhc->intf_name : NULL);
818 if (pnhc->nexthop.vrf_id != VRF_DEFAULT)
819 vty_out(vty, " nexthop-vrf %s", pnhc->vrf_name);
820
821 vty_out(vty, "\n");
822 }
823
824 static void vty_show_pbrms(struct vty *vty,
825 const struct pbr_map_sequence *pbrms, bool detail)
826 {
827 char rbuf[64];
828
829 if (pbrms->reason)
830 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
831
832 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
833
834 if (detail)
835 vty_out(vty, " Installed: %" PRIu64 "(%u) Reason: %s\n",
836 pbrms->installed, pbrms->unique,
837 pbrms->reason ? rbuf : "Valid");
838 else
839 vty_out(vty, " Installed: %s Reason: %s\n",
840 pbrms->installed ? "yes" : "no",
841 pbrms->reason ? rbuf : "Valid");
842
843 if (pbrms->ip_proto) {
844 struct protoent *p;
845
846 p = getprotobynumber(pbrms->ip_proto);
847 vty_out(vty, " IP Protocol Match: %s\n", p->p_name);
848 }
849
850 if (pbrms->src)
851 vty_out(vty, " SRC Match: %pFX\n", pbrms->src);
852 if (pbrms->dst)
853 vty_out(vty, " DST Match: %pFX\n", pbrms->dst);
854 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
855 vty_out(vty, " DSCP Match: %u\n",
856 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
857 if (pbrms->dsfield & PBR_DSFIELD_ECN)
858 vty_out(vty, " ECN Match: %u\n",
859 pbrms->dsfield & PBR_DSFIELD_ECN);
860 if (pbrms->mark)
861 vty_out(vty, " MARK Match: %u\n", pbrms->mark);
862
863 if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
864 vty_out(vty, " Set Queue ID %u\n",
865 pbrms->action_queue_id);
866
867 if (pbrms->action_vlan_id != 0)
868 vty_out(vty, " Set VLAN ID %u\n", pbrms->action_vlan_id);
869 if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
870 vty_out(vty, " Strip VLAN ID\n");
871 if (pbrms->action_pcp)
872 vty_out(vty, " Set PCP %u\n", pbrms->action_pcp);
873
874
875 if (pbrms->nhgrp_name) {
876 vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
877
878 if (detail)
879 vty_out(vty,
880 " Installed: %u(%d) Tableid: %d\n",
881 pbrms->nhs_installed,
882 pbr_nht_get_installed(pbrms->nhgrp_name),
883 pbr_nht_get_table(pbrms->nhgrp_name));
884 else
885 vty_out(vty, " Installed: %s Tableid: %d\n",
886 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
887 : "no",
888 pbr_nht_get_table(pbrms->nhgrp_name));
889
890 } else if (pbrms->nhg) {
891 vty_out(vty, " ");
892 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
893 if (detail)
894 vty_out(vty,
895 " Installed: %u(%d) Tableid: %d\n",
896 pbrms->nhs_installed,
897 pbr_nht_get_installed(pbrms->internal_nhg_name),
898 pbr_nht_get_table(pbrms->internal_nhg_name));
899 else
900 vty_out(vty, " Installed: %s Tableid: %d\n",
901 pbr_nht_get_installed(pbrms->internal_nhg_name)
902 ? "yes"
903 : "no",
904 pbr_nht_get_table(pbrms->internal_nhg_name));
905
906 } else if (pbrms->vrf_unchanged) {
907 vty_out(vty, " VRF Unchanged (use interface vrf)\n");
908 } else if (pbrms->vrf_lookup) {
909 vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name);
910 } else {
911 vty_out(vty, " Nexthop-Group: Unknown Installed: no\n");
912 }
913 }
914
915 static void vty_json_pbrms(json_object *j, struct vty *vty,
916 const struct pbr_map_sequence *pbrms)
917 {
918 json_object *jpbrm, *nexthop_group;
919 char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
920 : pbrms->internal_nhg_name;
921 char rbuf[64];
922
923 jpbrm = json_object_new_object();
924
925 json_object_int_add(jpbrm, "id", pbrms->unique);
926
927 if (pbrms->reason)
928 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
929
930 json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
931 json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
932 json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
933 json_object_boolean_add(jpbrm, "installed",
934 pbr_nht_get_installed(nhg_name));
935 json_object_string_add(jpbrm, "installedReason",
936 pbrms->reason ? rbuf : "Valid");
937
938 if (nhg_name) {
939 nexthop_group = json_object_new_object();
940
941 json_object_int_add(nexthop_group, "tableId",
942 pbr_nht_get_table(nhg_name));
943 json_object_string_add(nexthop_group, "name", nhg_name);
944 json_object_boolean_add(nexthop_group, "installed",
945 pbr_nht_get_installed(nhg_name));
946 json_object_int_add(nexthop_group, "installedInternally",
947 pbrms->nhs_installed);
948
949 json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
950 }
951
952 if (pbrms->vrf_lookup)
953 json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
954
955 if (pbrms->src)
956 json_object_string_addf(jpbrm, "matchSrc", "%pFX", pbrms->src);
957 if (pbrms->dst)
958 json_object_string_addf(jpbrm, "matchDst", "%pFX", pbrms->dst);
959 if (pbrms->mark)
960 json_object_int_add(jpbrm, "matchMark", pbrms->mark);
961 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
962 json_object_int_add(jpbrm, "matchDscp",
963 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
964 if (pbrms->dsfield & PBR_DSFIELD_ECN)
965 json_object_int_add(jpbrm, "matchEcn",
966 pbrms->dsfield & PBR_DSFIELD_ECN);
967
968 json_object_array_add(j, jpbrm);
969 }
970
971 static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
972 bool detail)
973 {
974 struct pbr_map_sequence *pbrms;
975 struct listnode *node;
976
977 vty_out(vty, " pbr-map %s valid: %s\n", pbrm->name,
978 pbrm->valid ? "yes" : "no");
979
980 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
981 vty_show_pbrms(vty, pbrms, detail);
982 }
983
984 static void vty_json_pbr_map(json_object *j, struct vty *vty,
985 const struct pbr_map *pbrm)
986 {
987 struct pbr_map_sequence *pbrms;
988 struct listnode *node;
989 json_object *jpbrms;
990
991 json_object_string_add(j, "name", pbrm->name);
992 json_object_boolean_add(j, "valid", pbrm->valid);
993
994 jpbrms = json_object_new_array();
995
996 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
997 vty_json_pbrms(jpbrms, vty, pbrms);
998
999 json_object_object_add(j, "policies", jpbrms);
1000 }
1001
1002 DEFPY (show_pbr_map,
1003 show_pbr_map_cmd,
1004 "show pbr map [NAME$name] [detail$detail|json$json]",
1005 SHOW_STR
1006 PBR_STR
1007 "PBR Map\n"
1008 "PBR Map Name\n"
1009 "Detailed information\n"
1010 JSON_STR)
1011 {
1012 struct pbr_map *pbrm;
1013 json_object *j = NULL;
1014
1015 if (json)
1016 j = json_object_new_array();
1017
1018 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
1019 json_object *this_map = NULL;
1020 if (name && strcmp(name, pbrm->name) != 0)
1021 continue;
1022
1023 if (j)
1024 this_map = json_object_new_object();
1025
1026 if (this_map) {
1027 vty_json_pbr_map(this_map, vty, pbrm);
1028
1029 json_object_array_add(j, this_map);
1030 continue;
1031 }
1032
1033 vty_show_pbr_map(vty, pbrm, detail);
1034 }
1035
1036 if (j)
1037 vty_json(vty, j);
1038
1039 return CMD_SUCCESS;
1040 }
1041
1042 DEFPY(show_pbr_nexthop_group,
1043 show_pbr_nexthop_group_cmd,
1044 "show pbr nexthop-groups [WORD$word] [json$json]",
1045 SHOW_STR
1046 PBR_STR
1047 "Nexthop Groups\n"
1048 "Optional Name of the nexthop group\n"
1049 JSON_STR)
1050 {
1051 json_object *j = NULL;
1052
1053 if (json)
1054 j = json_object_new_array();
1055
1056 if (j) {
1057 pbr_nht_json_nexthop_group(j, word);
1058
1059 vty_json(vty, j);
1060 } else
1061 pbr_nht_show_nexthop_group(vty, word);
1062
1063
1064 return CMD_SUCCESS;
1065 }
1066
1067 DEFPY (show_pbr_interface,
1068 show_pbr_interface_cmd,
1069 "show pbr interface [NAME$name] [json$json]",
1070 SHOW_STR
1071 PBR_STR
1072 "PBR Interface\n"
1073 "PBR Interface Name\n"
1074 JSON_STR)
1075 {
1076 struct interface *ifp;
1077 struct vrf *vrf;
1078 struct pbr_interface *pbr_ifp;
1079 json_object *j = NULL;
1080
1081 if (json)
1082 j = json_object_new_array();
1083
1084 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
1085 FOR_ALL_INTERFACES(vrf, ifp) {
1086 struct pbr_map *pbrm;
1087 json_object *this_iface = NULL;
1088
1089 if (j)
1090 this_iface = json_object_new_object();
1091
1092 if (!ifp->info) {
1093 json_object_free(this_iface);
1094 continue;
1095 }
1096
1097 if (name && strcmp(ifp->name, name) != 0) {
1098 json_object_free(this_iface);
1099 continue;
1100 }
1101
1102 pbr_ifp = ifp->info;
1103
1104 if (strcmp(pbr_ifp->mapname, "") == 0) {
1105 json_object_free(this_iface);
1106 continue;
1107 }
1108
1109 pbrm = pbrm_find(pbr_ifp->mapname);
1110
1111 if (this_iface) {
1112 json_object_string_add(this_iface, "name",
1113 ifp->name);
1114 json_object_int_add(this_iface, "index",
1115 ifp->ifindex);
1116 json_object_string_add(this_iface, "policy",
1117 pbr_ifp->mapname);
1118 json_object_boolean_add(this_iface, "valid",
1119 pbrm);
1120
1121 json_object_array_add(j, this_iface);
1122 continue;
1123 }
1124
1125 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
1126 ifp->ifindex, pbr_ifp->mapname);
1127 if (!pbrm)
1128 vty_out(vty, " (map doesn't exist)");
1129 vty_out(vty, "\n");
1130 }
1131 }
1132
1133 if (j)
1134 vty_json(vty, j);
1135
1136 return CMD_SUCCESS;
1137 }
1138
1139 /* PBR debugging CLI ------------------------------------------------------- */
1140
1141 static struct cmd_node debug_node = {
1142 .name = "debug",
1143 .node = DEBUG_NODE,
1144 .prompt = "",
1145 .config_write = pbr_debug_config_write,
1146 };
1147
1148 DEFPY(debug_pbr,
1149 debug_pbr_cmd,
1150 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
1151 NO_STR
1152 DEBUG_STR
1153 PBR_STR
1154 "Policy maps\n"
1155 "PBRD <-> Zebra communications\n"
1156 "Nexthop tracking\n"
1157 "Events\n")
1158 {
1159 uint32_t mode = DEBUG_NODE2MODE(vty->node);
1160
1161 if (map)
1162 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
1163 if (zebra)
1164 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
1165 if (nht)
1166 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
1167 if (events)
1168 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
1169
1170 /* no specific debug --> act on all of them */
1171 if (strmatch(argv[argc - 1]->text, "pbr"))
1172 pbr_debug_set_all(mode, !no);
1173
1174 return CMD_SUCCESS;
1175 }
1176
1177 DEFUN_NOSH(show_debugging_pbr,
1178 show_debugging_pbr_cmd,
1179 "show debugging [pbr]",
1180 SHOW_STR
1181 DEBUG_STR
1182 PBR_STR)
1183 {
1184 vty_out(vty, "PBR debugging status:\n");
1185
1186 pbr_debug_config_write_helper(vty, false);
1187
1188 return CMD_SUCCESS;
1189 }
1190
1191 /* ------------------------------------------------------------------------- */
1192
1193
1194 static int pbr_interface_config_write(struct vty *vty)
1195 {
1196 struct interface *ifp;
1197 struct vrf *vrf;
1198
1199 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1200 FOR_ALL_INTERFACES (vrf, ifp) {
1201 if_vty_config_start(vty, ifp);
1202
1203 if (ifp->desc)
1204 vty_out(vty, " description %s\n", ifp->desc);
1205
1206 pbr_map_write_interfaces(vty, ifp);
1207
1208 if_vty_config_end(vty);
1209 }
1210 }
1211
1212 return 1;
1213 }
1214
1215 static int pbr_vty_map_config_write(struct vty *vty);
1216 /* PBR map node structure. */
1217 static struct cmd_node pbr_map_node = {
1218 .name = "pbr-map",
1219 .node = PBRMAP_NODE,
1220 .parent_node = CONFIG_NODE,
1221 .prompt = "%s(config-pbr-map)# ",
1222 .config_write = pbr_vty_map_config_write,
1223 };
1224
1225 static int pbr_vty_map_config_write_sequence(struct vty *vty,
1226 struct pbr_map *pbrm,
1227 struct pbr_map_sequence *pbrms)
1228 {
1229 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
1230
1231 if (pbrms->src)
1232 vty_out(vty, " match src-ip %pFX\n", pbrms->src);
1233
1234 if (pbrms->dst)
1235 vty_out(vty, " match dst-ip %pFX\n", pbrms->dst);
1236
1237 if (pbrms->src_prt)
1238 vty_out(vty, " match src-port %u\n", pbrms->src_prt);
1239 if (pbrms->dst_prt)
1240 vty_out(vty, " match dst-port %u\n", pbrms->dst_prt);
1241
1242 if (pbrms->ip_proto) {
1243 struct protoent *p;
1244
1245 p = getprotobynumber(pbrms->ip_proto);
1246 vty_out(vty, " match ip-protocol %s\n", p->p_name);
1247 }
1248
1249 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
1250 vty_out(vty, " match dscp %u\n",
1251 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
1252
1253 if (pbrms->dsfield & PBR_DSFIELD_ECN)
1254 vty_out(vty, " match ecn %u\n",
1255 pbrms->dsfield & PBR_DSFIELD_ECN);
1256
1257 if (pbrms->mark)
1258 vty_out(vty, " match mark %u\n", pbrms->mark);
1259
1260
1261 if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
1262 vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id);
1263
1264 if (pbrms->action_pcp)
1265 vty_out(vty, " set pcp %d\n", pbrms->action_pcp);
1266
1267 if (pbrms->action_vlan_id)
1268 vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id);
1269
1270 if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
1271 vty_out(vty, " strip vlan any\n");
1272
1273 if (pbrms->vrf_unchanged)
1274 vty_out(vty, " set vrf unchanged\n");
1275
1276 if (pbrms->vrf_lookup)
1277 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
1278
1279 if (pbrms->nhgrp_name)
1280 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
1281
1282 if (pbrms->nhg) {
1283 vty_out(vty, " set ");
1284 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
1285 }
1286
1287 vty_out(vty, "exit\n");
1288 vty_out(vty, "!\n");
1289 return 1;
1290 }
1291
1292 static int pbr_vty_map_config_write(struct vty *vty)
1293 {
1294 struct pbr_map *pbrm;
1295
1296 pbr_nht_write_table_range(vty);
1297 pbr_nht_write_rule_range(vty);
1298
1299 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
1300 struct pbr_map_sequence *pbrms;
1301 struct listnode *node;
1302
1303 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
1304 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
1305 }
1306
1307 return 1;
1308 }
1309
1310 static void pbr_map_completer(vector comps, struct cmd_token *token)
1311 {
1312 struct pbr_map *pbrm;
1313
1314 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
1315 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
1316 }
1317
1318 static const struct cmd_variable_handler pbr_map_name[] = {
1319 {
1320 .tokenname = "PBRMAP", .completions = pbr_map_completer,
1321 },
1322 {
1323 .completions = NULL
1324 }
1325 };
1326
1327 extern struct zebra_privs_t pbr_privs;
1328
1329 void pbr_vty_init(void)
1330 {
1331 cmd_variable_handler_register(pbr_map_name);
1332
1333 vrf_cmd_init(NULL);
1334
1335 if_cmd_init(pbr_interface_config_write);
1336
1337 install_node(&pbr_map_node);
1338
1339 /* debug */
1340 install_node(&debug_node);
1341 install_element(ENABLE_NODE, &debug_pbr_cmd);
1342 install_element(CONFIG_NODE, &debug_pbr_cmd);
1343 install_element(ENABLE_NODE, &show_debugging_pbr_cmd);
1344
1345 install_default(PBRMAP_NODE);
1346
1347 install_element(CONFIG_NODE, &pbr_map_cmd);
1348 install_element(CONFIG_NODE, &no_pbr_map_cmd);
1349 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
1350 install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);
1351 install_element(INTERFACE_NODE, &pbr_policy_cmd);
1352 install_element(PBRMAP_NODE, &pbr_map_match_ip_proto_cmd);
1353 install_element(PBRMAP_NODE, &pbr_map_match_src_port_cmd);
1354 install_element(PBRMAP_NODE, &pbr_map_match_dst_port_cmd);
1355 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
1356 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
1357 install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
1358 install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
1359 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
1360 install_element(PBRMAP_NODE, &pbr_map_action_queue_id_cmd);
1361 install_element(PBRMAP_NODE, &pbr_map_action_strip_vlan_cmd);
1362 install_element(PBRMAP_NODE, &pbr_map_action_vlan_id_cmd);
1363 install_element(PBRMAP_NODE, &pbr_map_action_pcp_cmd);
1364 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
1365 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
1366 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
1367 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_cmd);
1368 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
1369 install_element(PBRMAP_NODE, &no_pbr_map_vrf_cmd);
1370 install_element(VIEW_NODE, &show_pbr_cmd);
1371 install_element(VIEW_NODE, &show_pbr_map_cmd);
1372 install_element(VIEW_NODE, &show_pbr_interface_cmd);
1373 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
1374 }