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