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