]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_vty.c
Merge pull request #5416 from mjstapp/re_nhe_pointer
[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
139 pbr_map_check(pbrms);
140
141 return CMD_SUCCESS;
142 }
143
144 DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
145 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
146 NO_STR
147 "Match the rest of the command\n"
148 "Choose the src ip or ipv6 prefix to use\n"
149 "v4 Prefix\n"
150 "v6 Prefix\n")
151 {
152 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
153
154 pbrms->family = prefix->family;
155
156 if (!no) {
157 if (prefix_same(pbrms->dst, prefix))
158 return CMD_SUCCESS;
159
160 if (!pbrms->dst)
161 pbrms->dst = prefix_new();
162 prefix_copy(pbrms->dst, prefix);
163 } else
164 prefix_free(&pbrms->dst);
165
166 pbr_map_check(pbrms);
167
168 return CMD_SUCCESS;
169 }
170
171 DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
172 "[no] match mark (1-4294967295)$mark",
173 NO_STR
174 "Match the rest of the command\n"
175 "Choose the mark value to use\n"
176 "mark\n")
177 {
178 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
179
180 #ifndef GNU_LINUX
181 vty_out(vty, "pbr marks are not supported on this platform");
182 return CMD_WARNING_CONFIG_FAILED;
183 #endif
184
185 if (!no) {
186 if (pbrms->mark == (uint32_t) mark)
187 return CMD_SUCCESS;
188 pbrms->mark = (uint32_t) mark;
189 } else {
190 pbrms->mark = 0;
191 }
192
193 pbr_map_check(pbrms);
194
195 return CMD_SUCCESS;
196 }
197
198 #define SET_VRF_EXISTS_STR \
199 "A `set vrf XX` command already exists, please remove that first\n"
200
201 DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
202 "[no] set nexthop-group NHGNAME$name",
203 NO_STR
204 "Set for the PBR-MAP\n"
205 "nexthop-group to use\n"
206 "The name of the nexthop-group\n")
207 {
208 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
209 struct nexthop_group_cmd *nhgc;
210
211 if (pbrms->nhg) {
212 vty_out(vty,
213 "A `set nexthop XX` command already exists, please remove that first\n");
214 return CMD_WARNING_CONFIG_FAILED;
215 }
216
217 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
218 vty_out(vty, SET_VRF_EXISTS_STR);
219 return CMD_WARNING_CONFIG_FAILED;
220 }
221
222 nhgc = nhgc_find(name);
223 if (!nhgc) {
224 vty_out(vty, "Specified nexthop-group %s does not exist\n",
225 name);
226 vty_out(vty,
227 "PBR-MAP will not be applied until it is created\n");
228 }
229
230 if (no) {
231 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
232 pbr_map_delete_nexthops(pbrms);
233 else {
234 vty_out(vty,
235 "Nexthop Group specified: %s does not exist to remove",
236 name);
237 return CMD_WARNING_CONFIG_FAILED;
238 }
239 } else {
240 if (pbrms->nhgrp_name) {
241 if (strcmp(name, pbrms->nhgrp_name) != 0) {
242 vty_out(vty,
243 "Please delete current nexthop group before modifying current one");
244 return CMD_WARNING_CONFIG_FAILED;
245 }
246
247 return CMD_SUCCESS;
248 }
249 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
250 pbr_map_check(pbrms);
251 }
252
253 return CMD_SUCCESS;
254 }
255
256 DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
257 "[no] set nexthop\
258 <\
259 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
260 |INTERFACE$intf\
261 >\
262 [nexthop-vrf NAME$vrf_name]",
263 NO_STR
264 "Set for the PBR-MAP\n"
265 "Specify one of the nexthops in this map\n"
266 "v4 Address\n"
267 "v6 Address\n"
268 "Interface to use\n"
269 "Interface to use\n"
270 "If the nexthop is in a different vrf tell us\n"
271 "The nexthop-vrf Name\n")
272 {
273 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
274 struct vrf *vrf;
275 struct nexthop nhop;
276 struct nexthop *nh;
277
278 if (pbrms->nhgrp_name) {
279 vty_out(vty,
280 "Please unconfigure the nexthop group before adding an individual nexthop");
281 return CMD_WARNING_CONFIG_FAILED;
282 }
283
284 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
285 vty_out(vty, SET_VRF_EXISTS_STR);
286 return CMD_WARNING_CONFIG_FAILED;
287 }
288
289 if (vrf_name)
290 vrf = vrf_lookup_by_name(vrf_name);
291 else
292 vrf = vrf_lookup_by_id(VRF_DEFAULT);
293
294 if (!vrf) {
295 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
296 return CMD_WARNING_CONFIG_FAILED;
297 }
298
299 memset(&nhop, 0, sizeof(nhop));
300 nhop.vrf_id = vrf->vrf_id;
301
302 if (intf) {
303 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
304 if (nhop.ifindex == IFINDEX_INTERNAL) {
305 vty_out(vty,
306 "Specified Intf %s does not exist in vrf: %s\n",
307 intf, vrf->name);
308 return CMD_WARNING_CONFIG_FAILED;
309 }
310 }
311
312 if (addr) {
313 if (addr->sa.sa_family == AF_INET) {
314 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
315 if (intf)
316 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
317 else
318 nhop.type = NEXTHOP_TYPE_IPV4;
319 } else {
320 nhop.gate.ipv6 = addr->sin6.sin6_addr;
321 if (intf)
322 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
323 else {
324 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
325 vty_out(vty,
326 "Specified a v6 LL with no interface, rejecting\n");
327 return CMD_WARNING_CONFIG_FAILED;
328 }
329 nhop.type = NEXTHOP_TYPE_IPV6;
330 }
331 }
332 } else
333 nhop.type = NEXTHOP_TYPE_IFINDEX;
334
335 if (pbrms->nhg)
336 nh = nexthop_exists(pbrms->nhg, &nhop);
337 else {
338 char buf[PBR_NHC_NAMELEN];
339
340 if (no) {
341 vty_out(vty, "No nexthops to delete\n");
342 return CMD_WARNING_CONFIG_FAILED;
343 }
344
345 pbrms->nhg = nexthop_group_new();
346 pbrms->internal_nhg_name =
347 XSTRDUP(MTYPE_TMP,
348 pbr_nht_nexthop_make_name(pbrms->parent->name,
349 PBR_NHC_NAMELEN,
350 pbrms->seqno,
351 buf));
352 nh = NULL;
353 }
354
355 if (no) {
356 if (nh)
357 pbr_nht_delete_individual_nexthop(pbrms);
358 } else if (!nh) {
359
360 if (pbrms->nhg->nexthop) {
361 vty_out(vty,
362 "If you would like more than one nexthop please use nexthop-groups");
363 return CMD_WARNING_CONFIG_FAILED;
364 }
365
366 /* must be adding new nexthop since !no and !nexthop_exists */
367 nh = nexthop_new();
368
369 memcpy(nh, &nhop, sizeof(nhop));
370 _nexthop_add(&pbrms->nhg->nexthop, nh);
371
372 pbr_nht_add_individual_nexthop(pbrms);
373 pbr_map_check(pbrms);
374 }
375
376 if (nhop.type == NEXTHOP_TYPE_IFINDEX
377 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
378 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
379 struct interface *ifp;
380
381 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
382 if (ifp)
383 pbr_nht_nexthop_interface_update(ifp);
384 }
385
386 return CMD_SUCCESS;
387 }
388
389 DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
390 "[no] set vrf <NAME$vrf_name|unchanged>",
391 NO_STR
392 "Set for the PBR-MAP\n"
393 "Specify the VRF for this map\n"
394 "The VRF Name\n"
395 "Use the interface's VRF for lookup\n")
396 {
397 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
398 int ret = CMD_SUCCESS;
399
400 if (no) {
401 pbr_map_delete_vrf(pbrms);
402
403 /* Reset all data */
404 pbrms->nhs_installed = false;
405 pbrms->vrf_name[0] = '\0';
406 pbrms->vrf_lookup = false;
407 pbrms->vrf_unchanged = false;
408
409 goto done;
410 }
411
412 if (pbrms->nhgrp_name || pbrms->nhg) {
413 vty_out(vty,
414 "A `set nexthop/nexthop-group XX` command already exits, please remove that first\n");
415 ret = CMD_WARNING_CONFIG_FAILED;
416 goto done;
417 }
418
419 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
420 vty_out(vty, SET_VRF_EXISTS_STR);
421 ret = CMD_WARNING_CONFIG_FAILED;
422 goto done;
423 }
424
425 if (vrf_name) {
426 if (!pbr_vrf_lookup_by_name(vrf_name)) {
427 vty_out(vty, "Specified: %s is non-existent\n",
428 vrf_name);
429 ret = CMD_WARNING_CONFIG_FAILED;
430 goto done;
431 }
432
433 pbrms->vrf_lookup = true;
434 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
435 } else
436 pbrms->vrf_unchanged = true;
437
438 pbr_map_check(pbrms);
439
440 done:
441 return ret;
442 }
443
444 DEFPY (pbr_policy,
445 pbr_policy_cmd,
446 "[no] pbr-policy PBRMAP$mapname",
447 NO_STR
448 "Policy to use\n"
449 "Name of the pbr-map to apply\n")
450 {
451 VTY_DECLVAR_CONTEXT(interface, ifp);
452 struct pbr_map *pbrm, *old_pbrm;
453 struct pbr_interface *pbr_ifp = ifp->info;
454
455 old_pbrm = NULL;
456 pbrm = pbrm_find(mapname);
457
458 if (!pbr_ifp) {
459 /* we don't want one and we don't have one, so... */
460 if (no)
461 return CMD_SUCCESS;
462
463 /* Some one could have fat fingered the interface name */
464 pbr_ifp = pbr_if_new(ifp);
465 }
466
467 if (no) {
468 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
469 pbr_ifp->mapname[0] = '\0';
470 if (pbrm)
471 pbr_map_interface_delete(pbrm, ifp);
472 }
473 } else {
474 if (strcmp(pbr_ifp->mapname, "") != 0) {
475 old_pbrm = pbrm_find(pbr_ifp->mapname);
476
477 /*
478 * So if we have an old pbrm we should only
479 * delete it if we are actually deleting and
480 * moving to a new pbrm
481 */
482 if (old_pbrm && old_pbrm != pbrm)
483 pbr_map_interface_delete(old_pbrm, ifp);
484 }
485 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
486 "%s", mapname);
487
488 /*
489 * So only reinstall if the old_pbrm and this pbrm are
490 * different.
491 */
492 if (pbrm && pbrm != old_pbrm)
493 pbr_map_add_interface(pbrm, ifp);
494 }
495
496 return CMD_SUCCESS;
497 }
498
499 DEFPY (show_pbr,
500 show_pbr_cmd,
501 "show pbr",
502 SHOW_STR
503 PBR_STR)
504 {
505 pbr_nht_write_table_range(vty);
506 pbr_nht_write_rule_range(vty);
507
508 return CMD_SUCCESS;
509 }
510
511 DEFPY (show_pbr_map,
512 show_pbr_map_cmd,
513 "show pbr map [NAME$name] [detail$detail]",
514 SHOW_STR
515 PBR_STR
516 "PBR Map\n"
517 "PBR Map Name\n"
518 "Detailed information\n")
519 {
520 struct pbr_map_sequence *pbrms;
521 struct pbr_map *pbrm;
522 struct listnode *node;
523 char buf[PREFIX_STRLEN];
524 char rbuf[64];
525
526 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
527 if (name && strcmp(name, pbrm->name) != 0)
528 continue;
529
530 vty_out(vty, " pbr-map %s valid: %d\n", pbrm->name,
531 pbrm->valid);
532
533 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
534 if (pbrms->reason)
535 pbr_map_reason_string(pbrms->reason, rbuf,
536 sizeof(rbuf));
537 vty_out(vty,
538 " Seq: %u rule: %u Installed: %" PRIu64 "(%u) Reason: %s\n",
539 pbrms->seqno, pbrms->ruleno, pbrms->installed,
540 pbrms->unique, pbrms->reason ? rbuf : "Valid");
541
542 if (pbrms->src)
543 vty_out(vty, "\tSRC Match: %s\n",
544 prefix2str(pbrms->src, buf,
545 sizeof(buf)));
546 if (pbrms->dst)
547 vty_out(vty, "\tDST Match: %s\n",
548 prefix2str(pbrms->dst, buf,
549 sizeof(buf)));
550 if (pbrms->mark)
551 vty_out(vty, "\tMARK Match: %u\n", pbrms->mark);
552
553 if (pbrms->nhgrp_name) {
554 vty_out(vty,
555 "\tNexthop-Group: %s(%u) Installed: %u(%d)\n",
556 pbrms->nhgrp_name,
557 pbr_nht_get_table(pbrms->nhgrp_name),
558 pbrms->nhs_installed,
559 pbr_nht_get_installed(
560 pbrms->nhgrp_name));
561 } else if (pbrms->nhg) {
562 vty_out(vty, " ");
563 nexthop_group_write_nexthop(
564 vty, pbrms->nhg->nexthop);
565 vty_out(vty,
566 "\tInstalled: %u(%d) Tableid: %d\n",
567 pbrms->nhs_installed,
568 pbr_nht_get_installed(
569 pbrms->internal_nhg_name),
570 pbr_nht_get_table(
571 pbrms->internal_nhg_name));
572 } else if (pbrms->vrf_unchanged) {
573 vty_out(vty,
574 "\tVRF Unchanged (use interface vrf)\n");
575 } else if (pbrms->vrf_lookup) {
576 vty_out(vty, "\tVRF Lookup: %s\n",
577 pbrms->vrf_name);
578 } else {
579 vty_out(vty,
580 "\tNexthop-Group: Unknown Installed: 0(0)\n");
581 }
582 }
583 }
584 return CMD_SUCCESS;
585 }
586
587 DEFPY(show_pbr_nexthop_group,
588 show_pbr_nexthop_group_cmd,
589 "show pbr nexthop-groups [WORD$word]",
590 SHOW_STR
591 PBR_STR
592 "Nexthop Groups\n"
593 "Optional Name of the nexthop group\n")
594 {
595 pbr_nht_show_nexthop_group(vty, word);
596
597 return CMD_SUCCESS;
598 }
599
600 DEFPY (show_pbr_interface,
601 show_pbr_interface_cmd,
602 "show pbr interface [NAME$name]",
603 SHOW_STR
604 PBR_STR
605 "PBR Interface\n"
606 "PBR Interface Name\n")
607 {
608 struct interface *ifp;
609 struct vrf *vrf;
610 struct pbr_interface *pbr_ifp;
611
612 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
613 FOR_ALL_INTERFACES(vrf, ifp) {
614 struct pbr_map *pbrm;
615
616 if (!ifp->info)
617 continue;
618
619 if (name && strcmp(ifp->name, name) != 0)
620 continue;
621
622 pbr_ifp = ifp->info;
623
624 if (strcmp(pbr_ifp->mapname, "") == 0)
625 continue;
626
627 pbrm = pbrm_find(pbr_ifp->mapname);
628 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
629 ifp->ifindex, pbr_ifp->mapname);
630 if (!pbrm)
631 vty_out(vty, " (map doesn't exist)");
632 vty_out(vty, "\n");
633 }
634 }
635
636 return CMD_SUCCESS;
637 }
638
639 /* PBR debugging CLI ------------------------------------------------------- */
640
641 static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
642
643 DEFPY(debug_pbr,
644 debug_pbr_cmd,
645 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
646 NO_STR
647 DEBUG_STR
648 PBR_STR
649 "Policy maps\n"
650 "PBRD <-> Zebra communications\n"
651 "Nexthop tracking\n"
652 "Events\n")
653 {
654 uint32_t mode = DEBUG_NODE2MODE(vty->node);
655
656 if (map)
657 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
658 if (zebra)
659 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
660 if (nht)
661 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
662 if (events)
663 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
664
665 /* no specific debug --> act on all of them */
666 if (strmatch(argv[argc - 1]->text, "pbr"))
667 pbr_debug_set_all(mode, !no);
668
669 return CMD_SUCCESS;
670 }
671
672 DEFUN_NOSH(show_debugging_pbr,
673 show_debugging_pbr_cmd,
674 "show debugging [pbr]",
675 SHOW_STR
676 DEBUG_STR
677 PBR_STR)
678 {
679 vty_out(vty, "PBR debugging status:\n");
680
681 pbr_debug_config_write_helper(vty, false);
682
683 return CMD_SUCCESS;
684 }
685
686 /* ------------------------------------------------------------------------- */
687
688
689 static struct cmd_node interface_node = {
690 INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
691 };
692
693 static int pbr_interface_config_write(struct vty *vty)
694 {
695 struct interface *ifp;
696 struct vrf *vrf;
697
698 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
699 FOR_ALL_INTERFACES (vrf, ifp) {
700 if (vrf->vrf_id == VRF_DEFAULT)
701 vty_frame(vty, "interface %s\n", ifp->name);
702 else
703 vty_frame(vty, "interface %s vrf %s\n",
704 ifp->name, vrf->name);
705
706 if (ifp->desc)
707 vty_out(vty, " description %s\n", ifp->desc);
708
709 pbr_map_write_interfaces(vty, ifp);
710
711 vty_endframe(vty, "!\n");
712 }
713 }
714
715 return 1;
716 }
717
718 /* PBR map node structure. */
719 static struct cmd_node pbr_map_node = {PBRMAP_NODE, "%s(config-pbr-map)# ", 1};
720
721 static int pbr_vty_map_config_write_sequence(struct vty *vty,
722 struct pbr_map *pbrm,
723 struct pbr_map_sequence *pbrms)
724 {
725 char buff[PREFIX_STRLEN];
726
727 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
728
729 if (pbrms->src)
730 vty_out(vty, " match src-ip %s\n",
731 prefix2str(pbrms->src, buff, sizeof(buff)));
732
733 if (pbrms->dst)
734 vty_out(vty, " match dst-ip %s\n",
735 prefix2str(pbrms->dst, buff, sizeof(buff)));
736
737 if (pbrms->mark)
738 vty_out(vty, " match mark %u\n", pbrms->mark);
739
740 if (pbrms->vrf_unchanged)
741 vty_out(vty, " set vrf unchanged\n");
742
743 if (pbrms->vrf_lookup)
744 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
745
746 if (pbrms->nhgrp_name)
747 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
748
749 if (pbrms->nhg) {
750 vty_out(vty, " set ");
751 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
752 }
753
754 vty_out(vty, "!\n");
755 return 1;
756 }
757
758 static int pbr_vty_map_config_write(struct vty *vty)
759 {
760 struct pbr_map *pbrm;
761
762 pbr_nht_write_table_range(vty);
763 pbr_nht_write_rule_range(vty);
764
765 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
766 struct pbr_map_sequence *pbrms;
767 struct listnode *node;
768
769 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
770 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
771 }
772
773 return 1;
774 }
775
776 static void pbr_map_completer(vector comps, struct cmd_token *token)
777 {
778 struct pbr_map *pbrm;
779
780 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
781 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
782 }
783
784 static const struct cmd_variable_handler pbr_map_name[] = {
785 {
786 .tokenname = "PBRMAP", .completions = pbr_map_completer,
787 },
788 {
789 .completions = NULL
790 }
791 };
792
793 void pbr_vty_init(void)
794 {
795 cmd_variable_handler_register(pbr_map_name);
796
797 install_node(&interface_node,
798 pbr_interface_config_write);
799 if_cmd_init();
800
801 install_node(&pbr_map_node,
802 pbr_vty_map_config_write);
803
804 /* debug */
805 install_node(&debug_node, pbr_debug_config_write);
806 install_element(VIEW_NODE, &debug_pbr_cmd);
807 install_element(CONFIG_NODE, &debug_pbr_cmd);
808 install_element(VIEW_NODE, &show_debugging_pbr_cmd);
809
810 install_default(PBRMAP_NODE);
811
812 install_element(CONFIG_NODE, &pbr_map_cmd);
813 install_element(CONFIG_NODE, &no_pbr_map_cmd);
814 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
815 install_element(INTERFACE_NODE, &pbr_policy_cmd);
816 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
817 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
818 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
819 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
820 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
821 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
822 install_element(VIEW_NODE, &show_pbr_cmd);
823 install_element(VIEW_NODE, &show_pbr_map_cmd);
824 install_element(VIEW_NODE, &show_pbr_interface_cmd);
825 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
826 }