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