]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_vty.c
pbrd: Allow autocompletion for pbr-map PBRMAP
[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 "log.h"
29 #include "debug.h"
30 #include "pbr.h"
31
32 #include "pbrd/pbr_nht.h"
33 #include "pbrd/pbr_map.h"
34 #include "pbrd/pbr_zebra.h"
35 #include "pbrd/pbr_vty.h"
36 #include "pbrd/pbr_debug.h"
37 #ifndef VTYSH_EXTRACT_PL
38 #include "pbrd/pbr_vty_clippy.c"
39 #endif
40
41 DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
42 "Create pbr-map or enter pbr-map command mode\n"
43 "The name of the PBR MAP\n"
44 "Sequence to insert in existing pbr-map entry\n"
45 "Sequence number\n")
46 {
47 const char *pbrm_name = argv[1]->arg;
48 uint32_t seqno = atoi(argv[3]->arg);
49 struct pbr_map_sequence *pbrms;
50
51 pbrms = pbrms_get(pbrm_name, seqno);
52 VTY_PUSH_CONTEXT(PBRMAP_NODE, pbrms);
53
54 return CMD_SUCCESS;
55 }
56
57 DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
58 NO_STR
59 "Delete pbr-map\n"
60 "The name of the PBR MAP\n"
61 "Sequence to delete from existing pbr-map entry\n"
62 "Sequence number\n")
63 {
64 const char *pbrm_name = argv[2]->arg;
65 uint32_t seqno = 0;
66 struct pbr_map *pbrm = pbrm_find(pbrm_name);
67 struct pbr_map_sequence *pbrms;
68 struct listnode *node, *next_node;
69
70 if (argc > 3)
71 seqno = atoi(argv[4]->arg);
72
73 if (!pbrm) {
74 vty_out(vty, "pbr-map %s not found\n", pbrm_name);
75 return CMD_SUCCESS;
76 }
77
78 for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, next_node, pbrms)) {
79 if (seqno && pbrms->seqno != seqno)
80 continue;
81
82 pbr_map_delete(pbrms);
83 }
84
85 return CMD_SUCCESS;
86 }
87
88 DEFPY(pbr_set_table_range,
89 pbr_set_table_range_cmd,
90 "[no] pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
91 NO_STR
92 PBR_STR
93 "Set table ID range\n"
94 "Set table ID range\n"
95 "Lower bound for table ID range\n"
96 "Upper bound for table ID range\n")
97 {
98 /* upper bound is 2^32 - 2^10 */
99 int ret = CMD_WARNING;
100 const int minrange = 1000;
101
102 /* validate given bounds */
103 if (lb > ub)
104 vty_out(vty, "%% Lower bound must be less than upper bound\n");
105 else if (ub - lb < minrange)
106 vty_out(vty, "%% Range breadth must be at least %d\n", minrange);
107 else {
108 ret = CMD_SUCCESS;
109 pbr_nht_set_tableid_range((uint32_t) lb, (uint32_t) ub);
110 }
111
112 return ret;
113 }
114
115
116 DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
117 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
118 NO_STR
119 "Match the rest of the command\n"
120 "Choose the src ip or ipv6 prefix to use\n"
121 "v4 Prefix\n"
122 "v6 Prefix\n")
123 {
124 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
125
126 pbrms->family = prefix->family;
127
128 if (!no) {
129 if (prefix_same(pbrms->src, prefix))
130 return CMD_SUCCESS;
131
132 if (!pbrms->src)
133 pbrms->src = prefix_new();
134 prefix_copy(pbrms->src, prefix);
135 } else {
136 prefix_free(pbrms->src);
137 pbrms->src = 0;
138 }
139
140 pbr_map_check(pbrms);
141
142 return CMD_SUCCESS;
143 }
144
145 DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
146 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
147 NO_STR
148 "Match the rest of the command\n"
149 "Choose the src ip or ipv6 prefix to use\n"
150 "v4 Prefix\n"
151 "v6 Prefix\n")
152 {
153 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
154
155 pbrms->family = prefix->family;
156
157 if (!no) {
158 if (prefix_same(pbrms->dst, prefix))
159 return CMD_SUCCESS;
160
161 if (!pbrms->dst)
162 pbrms->dst = prefix_new();
163 prefix_copy(pbrms->dst, prefix);
164 } else {
165 prefix_free(pbrms->dst);
166 pbrms->dst = NULL;
167 }
168
169 pbr_map_check(pbrms);
170
171 return CMD_SUCCESS;
172 }
173
174 DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
175 "[no] set nexthop-group NHGNAME$name",
176 NO_STR
177 "Set for the PBR-MAP\n"
178 "nexthop-group to use\n"
179 "The name of the nexthop-group\n")
180 {
181 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
182 struct nexthop_group_cmd *nhgc;
183
184 if (pbrms->nhg) {
185 vty_out(vty,
186 "A `set nexthop XX` command already exists, please remove that first\n");
187 return CMD_WARNING_CONFIG_FAILED;
188 }
189
190 nhgc = nhgc_find(name);
191 if (!nhgc) {
192 vty_out(vty, "Specified nexthop-group %s does not exist\n",
193 name);
194 vty_out(vty, "PBR-MAP will not be applied until it is created\n");
195 }
196
197 if (no) {
198 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
199 pbr_map_delete_nexthop_group(pbrms);
200 else {
201 vty_out(vty,
202 "Nexthop Group specified: %s does not exist to remove",
203 name);
204 return CMD_WARNING_CONFIG_FAILED;
205 }
206 } else {
207 if (pbrms->nhgrp_name) {
208 if (strcmp(name, pbrms->nhgrp_name) != 0) {
209 vty_out(vty,
210 "Please delete current nexthop group before modifying current one");
211 return CMD_WARNING_CONFIG_FAILED;
212 }
213
214 return CMD_SUCCESS;
215 }
216 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
217 pbr_map_check(pbrms);
218 }
219
220 return CMD_SUCCESS;
221 }
222
223 DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
224 "[no] set nexthop\
225 <\
226 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
227 |INTERFACE$intf\
228 >\
229 [nexthop-vrf NAME$name]",
230 NO_STR
231 "Set for the PBR-MAP\n"
232 "Specify one of the nexthops in this map\n"
233 "v4 Address\n"
234 "v6 Address\n"
235 "Interface to use\n"
236 "Interface to use\n"
237 "If the nexthop is in a different vrf tell us\n"
238 "The nexthop-vrf Name\n")
239 {
240 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
241 struct vrf *vrf;
242 struct nexthop nhop;
243 struct nexthop *nh;
244
245 if (pbrms->nhgrp_name) {
246 vty_out(vty,
247 "Please unconfigure the nexthop group before adding an individual nexthop");
248 return CMD_WARNING_CONFIG_FAILED;
249 }
250
251 if (name)
252 vrf = vrf_lookup_by_name(name);
253 else
254 vrf = vrf_lookup_by_id(VRF_DEFAULT);
255
256 if (!vrf) {
257 vty_out(vty, "Specified: %s is non-existent\n", name);
258 return CMD_WARNING_CONFIG_FAILED;
259 }
260
261 memset(&nhop, 0, sizeof(nhop));
262 nhop.vrf_id = vrf->vrf_id;
263
264 if (intf) {
265 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
266 if (nhop.ifindex == IFINDEX_INTERNAL) {
267 vty_out(vty,
268 "Specified Intf %s does not exist in vrf: %s\n",
269 intf, vrf->name);
270 return CMD_WARNING_CONFIG_FAILED;
271 }
272 }
273
274 if (addr) {
275 if (addr->sa.sa_family == AF_INET) {
276 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
277 if (intf)
278 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
279 else
280 nhop.type = NEXTHOP_TYPE_IPV4;
281 } else {
282 nhop.gate.ipv6 = addr->sin6.sin6_addr;
283 if (intf)
284 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
285 else {
286 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
287 vty_out(vty,
288 "Specified a v6 LL with no interface, rejecting\n");
289 return CMD_WARNING_CONFIG_FAILED;
290 }
291 nhop.type = NEXTHOP_TYPE_IPV6;
292 }
293 }
294 } else
295 nhop.type = NEXTHOP_TYPE_IFINDEX;
296
297 if (pbrms->nhg)
298 nh = nexthop_exists(pbrms->nhg, &nhop);
299 else {
300 char buf[PBR_NHC_NAMELEN];
301
302 if (no) {
303 vty_out(vty, "No nexthops to delete\n");
304 return CMD_WARNING_CONFIG_FAILED;
305 }
306
307 pbrms->nhg = nexthop_group_new();
308 pbrms->internal_nhg_name =
309 XSTRDUP(MTYPE_TMP,
310 pbr_nht_nexthop_make_name(pbrms->parent->name,
311 PBR_NHC_NAMELEN,
312 pbrms->seqno,
313 buf));
314 nh = NULL;
315 }
316
317 if (no) {
318 if (nh)
319 pbr_nht_delete_individual_nexthop(pbrms);
320 } else if (!nh) {
321
322 if (pbrms->nhg->nexthop) {
323 vty_out(vty,
324 "If you would like more than one nexthop please use nexthop-groups");
325 return CMD_WARNING_CONFIG_FAILED;
326 }
327
328 /* must be adding new nexthop since !no and !nexthop_exists */
329 nh = nexthop_new();
330
331 memcpy(nh, &nhop, sizeof(nhop));
332 nexthop_add(&pbrms->nhg->nexthop, nh);
333
334 pbr_nht_add_individual_nexthop(pbrms);
335 pbr_map_check(pbrms);
336 }
337
338 if (nhop.type == NEXTHOP_TYPE_IFINDEX) {
339 struct interface *ifp;
340
341 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
342 if (ifp)
343 pbr_nht_nexthop_interface_update(ifp);
344 }
345
346 return CMD_SUCCESS;
347 }
348
349 DEFPY (pbr_policy,
350 pbr_policy_cmd,
351 "[no] pbr-policy PBRMAP$mapname",
352 NO_STR
353 "Policy to use\n"
354 "Name of the pbr-map to apply\n")
355 {
356 VTY_DECLVAR_CONTEXT(interface, ifp);
357 struct pbr_map *pbrm, *old_pbrm;
358 struct pbr_interface *pbr_ifp = ifp->info;
359
360 old_pbrm = NULL;
361 pbrm = pbrm_find(mapname);
362
363 if (!pbr_ifp) {
364 /* we don't want one and we don't have one, so... */
365 if (no)
366 return CMD_SUCCESS;
367
368 /* Some one could have fat fingered the interface name */
369 pbr_ifp = pbr_if_new(ifp);
370 }
371
372 if (no) {
373 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
374 pbr_ifp->mapname[0] = '\0';
375 if (pbrm)
376 pbr_map_interface_delete(pbrm, ifp);
377 }
378 } else {
379 if (strcmp(pbr_ifp->mapname, "") != 0) {
380 old_pbrm = pbrm_find(pbr_ifp->mapname);
381
382 /*
383 * So if we have an old pbrm we should only
384 * delete it if we are actually deleting and
385 * moving to a new pbrm
386 */
387 if (old_pbrm && old_pbrm != pbrm)
388 pbr_map_interface_delete(old_pbrm, ifp);
389 }
390 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
391 "%s", mapname);
392
393 /*
394 * So only reinstall if the old_pbrm and this pbrm are
395 * different.
396 */
397 if (pbrm && pbrm != old_pbrm)
398 pbr_map_add_interface(pbrm, ifp);
399 }
400
401 return CMD_SUCCESS;
402 }
403
404 DEFPY (show_pbr,
405 show_pbr_cmd,
406 "show pbr",
407 SHOW_STR
408 PBR_STR)
409 {
410 pbr_nht_write_table_range(vty);
411 pbr_nht_write_rule_range(vty);
412
413 return CMD_SUCCESS;
414 }
415
416 DEFPY (show_pbr_map,
417 show_pbr_map_cmd,
418 "show pbr map [NAME$name] [detail$detail]",
419 SHOW_STR
420 PBR_STR
421 "PBR Map\n"
422 "PBR Map Name\n"
423 "Detailed information\n")
424 {
425 struct pbr_map_sequence *pbrms;
426 struct pbr_map *pbrm;
427 struct listnode *node;
428 char buf[PREFIX_STRLEN];
429 char rbuf[64];
430
431 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
432 if (name && strcmp(name, pbrm->name) != 0)
433 continue;
434
435 vty_out(vty, " pbr-map %s valid: %d\n", pbrm->name,
436 pbrm->valid);
437
438 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
439 if (pbrms->reason)
440 pbr_map_reason_string(pbrms->reason, rbuf,
441 sizeof(rbuf));
442 vty_out(vty,
443 " Seq: %u rule: %u Installed: %" PRIu64 "(%u) Reason: %s\n",
444 pbrms->seqno, pbrms->ruleno, pbrms->installed,
445 pbrms->unique, pbrms->reason ? rbuf : "Valid");
446
447 if (pbrms->src)
448 vty_out(vty, "\tSRC Match: %s\n",
449 prefix2str(pbrms->src, buf,
450 sizeof(buf)));
451 if (pbrms->dst)
452 vty_out(vty, "\tDST Match: %s\n",
453 prefix2str(pbrms->dst, buf,
454 sizeof(buf)));
455
456 if (pbrms->nhgrp_name) {
457 vty_out(vty,
458 "\tNexthop-Group: %s(%u) Installed: %u(%d)\n",
459 pbrms->nhgrp_name,
460 pbr_nht_get_table(pbrms->nhgrp_name),
461 pbrms->nhs_installed,
462 pbr_nht_get_installed(
463 pbrms->nhgrp_name));
464 } else if (pbrms->nhg) {
465 vty_out(vty, " ");
466 nexthop_group_write_nexthop(
467 vty, pbrms->nhg->nexthop);
468 vty_out(vty,
469 "\tInstalled: %u(%d) Tableid: %d\n",
470 pbrms->nhs_installed,
471 pbr_nht_get_installed(
472 pbrms->internal_nhg_name),
473 pbr_nht_get_table(
474 pbrms->internal_nhg_name));
475 } else {
476 vty_out(vty,
477 "\tNexthop-Group: Unknown Installed: 0(0)\n");
478 }
479 }
480 }
481 return CMD_SUCCESS;
482 }
483
484 DEFPY(show_pbr_nexthop_group,
485 show_pbr_nexthop_group_cmd,
486 "show pbr nexthop-groups [WORD$word]",
487 SHOW_STR
488 PBR_STR
489 "Nexthop Groups\n"
490 "Optional Name of the nexthop group\n")
491 {
492 pbr_nht_show_nexthop_group(vty, word);
493
494 return CMD_SUCCESS;
495 }
496
497 DEFPY (show_pbr_interface,
498 show_pbr_interface_cmd,
499 "show pbr interface [NAME$name]",
500 SHOW_STR
501 PBR_STR
502 "PBR Interface\n"
503 "PBR Interface Name\n")
504 {
505 struct interface *ifp;
506 struct vrf *vrf;
507 struct pbr_interface *pbr_ifp;
508
509 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
510 FOR_ALL_INTERFACES(vrf, ifp) {
511 struct pbr_map *pbrm;
512
513 if (!ifp->info)
514 continue;
515
516 if (name && strcmp(ifp->name, name) != 0)
517 continue;
518
519 pbr_ifp = ifp->info;
520
521 if (strcmp(pbr_ifp->mapname, "") == 0)
522 continue;
523
524 pbrm = pbrm_find(pbr_ifp->mapname);
525 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
526 ifp->ifindex, pbr_ifp->mapname);
527 if (!pbrm)
528 vty_out(vty, " (map doesn't exist)");
529 vty_out(vty, "\n");
530 }
531 }
532
533 return CMD_SUCCESS;
534 }
535
536 /* PBR debugging CLI ------------------------------------------------------- */
537
538 static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
539
540 DEFPY(debug_pbr,
541 debug_pbr_cmd,
542 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
543 NO_STR
544 DEBUG_STR
545 PBR_STR
546 "Policy maps\n"
547 "PBRD <-> Zebra communications\n"
548 "Nexthop tracking\n"
549 "Events\n")
550 {
551 uint32_t mode = DEBUG_NODE2MODE(vty->node);
552
553 if (map)
554 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
555 if (zebra)
556 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
557 if (nht)
558 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
559 if (events)
560 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
561
562 /* no specific debug --> act on all of them */
563 if (strmatch(argv[argc - 1]->text, "pbr"))
564 pbr_debug_set_all(mode, !no);
565
566 return CMD_SUCCESS;
567 }
568
569 DEFUN_NOSH(show_debugging_pbr,
570 show_debugging_pbr_cmd,
571 "show debugging [pbr]",
572 SHOW_STR
573 DEBUG_STR
574 PBR_STR)
575 {
576 vty_out(vty, "PBR debugging status:\n");
577
578 pbr_debug_config_write_helper(vty, false);
579
580 return CMD_SUCCESS;
581 }
582
583 /* ------------------------------------------------------------------------- */
584
585
586 static struct cmd_node interface_node = {
587 INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
588 };
589
590 static int pbr_interface_config_write(struct vty *vty)
591 {
592 struct interface *ifp;
593 struct vrf *vrf;
594
595 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
596 FOR_ALL_INTERFACES (vrf, ifp) {
597 if (vrf->vrf_id == VRF_DEFAULT)
598 vty_frame(vty, "interface %s\n", ifp->name);
599 else
600 vty_frame(vty, "interface %s vrf %s\n",
601 ifp->name, vrf->name);
602
603 if (ifp->desc)
604 vty_out(vty, " description %s\n", ifp->desc);
605
606 pbr_map_write_interfaces(vty, ifp);
607
608 vty_endframe(vty, "!\n");
609 }
610 }
611
612 return 1;
613 }
614
615 /* PBR map node structure. */
616 static struct cmd_node pbr_map_node = {PBRMAP_NODE, "%s(config-pbr-map)# ", 1};
617
618 static int pbr_vty_map_config_write_sequence(struct vty *vty,
619 struct pbr_map *pbrm,
620 struct pbr_map_sequence *pbrms)
621 {
622 char buff[PREFIX_STRLEN];
623
624 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
625
626 if (pbrms->src)
627 vty_out(vty, " match src-ip %s\n",
628 prefix2str(pbrms->src, buff, sizeof(buff)));
629
630 if (pbrms->dst)
631 vty_out(vty, " match dst-ip %s\n",
632 prefix2str(pbrms->dst, buff, sizeof(buff)));
633
634 if (pbrms->nhgrp_name)
635 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
636
637 if (pbrms->nhg) {
638 vty_out(vty, " set ");
639 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
640 }
641
642 vty_out(vty, "!\n");
643 return 1;
644 }
645
646 static int pbr_vty_map_config_write(struct vty *vty)
647 {
648 struct pbr_map *pbrm;
649
650 pbr_nht_write_table_range(vty);
651 pbr_nht_write_rule_range(vty);
652
653 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
654 struct pbr_map_sequence *pbrms;
655 struct listnode *node;
656
657 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
658 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
659 }
660
661 return 1;
662 }
663
664 static void pbr_map_completer(vector comps, struct cmd_token *token)
665 {
666 struct pbr_map *pbrm;
667
668 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
669 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
670 }
671
672 static const struct cmd_variable_handler pbr_map_name[] = {
673 {
674 .tokenname = "PBRMAP", .completions = pbr_map_completer,
675 },
676 {
677 .completions = NULL
678 }
679 };
680
681 void pbr_vty_init(void)
682 {
683 cmd_variable_handler_register(pbr_map_name);
684
685 install_node(&interface_node,
686 pbr_interface_config_write);
687 if_cmd_init();
688
689 install_node(&pbr_map_node,
690 pbr_vty_map_config_write);
691
692 /* debug */
693 install_node(&debug_node, pbr_debug_config_write);
694 install_element(VIEW_NODE, &debug_pbr_cmd);
695 install_element(CONFIG_NODE, &debug_pbr_cmd);
696 install_element(VIEW_NODE, &show_debugging_pbr_cmd);
697
698 install_default(PBRMAP_NODE);
699
700 install_element(CONFIG_NODE, &pbr_map_cmd);
701 install_element(CONFIG_NODE, &no_pbr_map_cmd);
702 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
703 install_element(INTERFACE_NODE, &pbr_policy_cmd);
704 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
705 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
706 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
707 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
708 install_element(VIEW_NODE, &show_pbr_cmd);
709 install_element(VIEW_NODE, &show_pbr_map_cmd);
710 install_element(VIEW_NODE, &show_pbr_interface_cmd);
711 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
712 }