]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_vty.c
doc: add show pbr map doc
[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
1eaa8361
SW
527static void vty_show_pbrms(struct vty *vty,
528 const struct pbr_map_sequence *pbrms, bool detail)
529{
530 char buf[PREFIX_STRLEN];
531 char rbuf[64];
532
533 if (pbrms->reason)
534 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
3259cde6
SW
535
536 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
537
538 if (detail)
add5e0a4 539 vty_out(vty, "\tInstalled: %" PRIu64 "(%u) Reason: %s\n",
3259cde6
SW
540 pbrms->installed, pbrms->unique,
541 pbrms->reason ? rbuf : "Valid");
542 else
add5e0a4 543 vty_out(vty, "\tInstalled: %s Reason: %s\n",
3259cde6
SW
544 pbrms->installed ? "yes" : "no",
545 pbrms->reason ? rbuf : "Valid");
1eaa8361
SW
546
547 if (pbrms->src)
548 vty_out(vty, "\tSRC Match: %s\n",
549 prefix2str(pbrms->src, buf, sizeof(buf)));
550 if (pbrms->dst)
551 vty_out(vty, "\tDST Match: %s\n",
552 prefix2str(pbrms->dst, buf, sizeof(buf)));
553 if (pbrms->mark)
554 vty_out(vty, "\tMARK Match: %u\n", pbrms->mark);
555
556 if (pbrms->nhgrp_name) {
add5e0a4
SW
557 vty_out(vty, "\tNexthop-Group: %s\n", pbrms->nhgrp_name);
558
3259cde6 559 if (detail)
add5e0a4 560 vty_out(vty, "\t\tInstalled: %u(%d) Tableid: %d\n",
3259cde6 561 pbrms->nhs_installed,
add5e0a4
SW
562 pbr_nht_get_installed(pbrms->nhgrp_name),
563 pbr_nht_get_table(pbrms->nhgrp_name));
3259cde6 564 else
add5e0a4
SW
565 vty_out(vty, "\t\tInstalled: %s Tableid: %d\n",
566 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
567 : "no",
568 pbr_nht_get_table(pbrms->nhgrp_name));
569
1eaa8361 570 } else if (pbrms->nhg) {
add5e0a4 571 vty_out(vty, "\t");
1eaa8361 572 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
3259cde6 573 if (detail)
add5e0a4 574 vty_out(vty, "\t\tInstalled: %u(%d) Tableid: %d\n",
3259cde6
SW
575 pbrms->nhs_installed,
576 pbr_nht_get_installed(pbrms->internal_nhg_name),
577 pbr_nht_get_table(pbrms->internal_nhg_name));
578 else
add5e0a4 579 vty_out(vty, "\t\tInstalled: %s Tableid: %d\n",
3259cde6
SW
580 pbr_nht_get_installed(pbrms->internal_nhg_name)
581 ? "yes"
582 : "no",
583 pbr_nht_get_table(pbrms->internal_nhg_name));
584
1eaa8361
SW
585 } else if (pbrms->vrf_unchanged) {
586 vty_out(vty, "\tVRF Unchanged (use interface vrf)\n");
587 } else if (pbrms->vrf_lookup) {
588 vty_out(vty, "\tVRF Lookup: %s\n", pbrms->vrf_name);
589 } else {
3259cde6 590 vty_out(vty, "\tNexthop-Group: Unknown Installed: no\n");
1eaa8361
SW
591 }
592}
593
594static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
595 bool detail)
596{
597 struct pbr_map_sequence *pbrms;
598 struct listnode *node;
599
600 vty_out(vty, " pbr-map %s valid: %d\n", pbrm->name, pbrm->valid);
601
602 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
603 vty_show_pbrms(vty, pbrms, detail);
604}
605
e5c83d9b
DS
606DEFPY (show_pbr_map,
607 show_pbr_map_cmd,
ef18ed6e 608 "show pbr map [NAME$name] [detail$detail]",
e5c83d9b 609 SHOW_STR
24a21176 610 PBR_STR
e5c83d9b
DS
611 "PBR Map\n"
612 "PBR Map Name\n"
ef18ed6e 613 "Detailed information\n")
e5c83d9b 614{
e5c83d9b 615 struct pbr_map *pbrm;
e5c83d9b
DS
616
617 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
618 if (name && strcmp(name, pbrm->name) != 0)
619 continue;
620
1eaa8361 621 vty_show_pbr_map(vty, pbrm, detail);
e5c83d9b
DS
622 }
623 return CMD_SUCCESS;
624}
625
626DEFPY(show_pbr_nexthop_group,
627 show_pbr_nexthop_group_cmd,
628 "show pbr nexthop-groups [WORD$word]",
629 SHOW_STR
24a21176 630 PBR_STR
e5c83d9b
DS
631 "Nexthop Groups\n"
632 "Optional Name of the nexthop group\n")
633{
634 pbr_nht_show_nexthop_group(vty, word);
635
636 return CMD_SUCCESS;
637}
638
639DEFPY (show_pbr_interface,
640 show_pbr_interface_cmd,
ef18ed6e 641 "show pbr interface [NAME$name]",
e5c83d9b 642 SHOW_STR
24a21176 643 PBR_STR
e5c83d9b 644 "PBR Interface\n"
ef18ed6e 645 "PBR Interface Name\n")
e5c83d9b 646{
d3765386 647 struct interface *ifp;
e5c83d9b
DS
648 struct vrf *vrf;
649 struct pbr_interface *pbr_ifp;
650
651 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
652 FOR_ALL_INTERFACES(vrf, ifp) {
653 struct pbr_map *pbrm;
654
1c33fb1d
DS
655 if (!ifp->info)
656 continue;
657
e5c83d9b
DS
658 if (name && strcmp(ifp->name, name) != 0)
659 continue;
660
661 pbr_ifp = ifp->info;
662
663 if (strcmp(pbr_ifp->mapname, "") == 0)
664 continue;
665
666 pbrm = pbrm_find(pbr_ifp->mapname);
667 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
668 ifp->ifindex, pbr_ifp->mapname);
669 if (!pbrm)
670 vty_out(vty, " (map doesn't exist)");
671 vty_out(vty, "\n");
672 }
673 }
674
675 return CMD_SUCCESS;
676}
677
e14f43cc 678/* PBR debugging CLI ------------------------------------------------------- */
e14f43cc
QY
679
680static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
681
682DEFPY(debug_pbr,
683 debug_pbr_cmd,
684 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
685 NO_STR
686 DEBUG_STR
24a21176 687 PBR_STR
e14f43cc
QY
688 "Policy maps\n"
689 "PBRD <-> Zebra communications\n"
690 "Nexthop tracking\n"
691 "Events\n")
692{
693 uint32_t mode = DEBUG_NODE2MODE(vty->node);
694
695 if (map)
696 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
697 if (zebra)
698 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
699 if (nht)
700 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
701 if (events)
702 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
703
704 /* no specific debug --> act on all of them */
705 if (strmatch(argv[argc - 1]->text, "pbr"))
706 pbr_debug_set_all(mode, !no);
707
708 return CMD_SUCCESS;
709}
710
711DEFUN_NOSH(show_debugging_pbr,
712 show_debugging_pbr_cmd,
713 "show debugging [pbr]",
714 SHOW_STR
715 DEBUG_STR
24a21176 716 PBR_STR)
e14f43cc
QY
717{
718 vty_out(vty, "PBR debugging status:\n");
719
720 pbr_debug_config_write_helper(vty, false);
721
722 return CMD_SUCCESS;
723}
724
e14f43cc
QY
725/* ------------------------------------------------------------------------- */
726
727
e5c83d9b
DS
728static struct cmd_node interface_node = {
729 INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
730};
731
732static int pbr_interface_config_write(struct vty *vty)
733{
734 struct interface *ifp;
735 struct vrf *vrf;
736
737 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
738 FOR_ALL_INTERFACES (vrf, ifp) {
739 if (vrf->vrf_id == VRF_DEFAULT)
740 vty_frame(vty, "interface %s\n", ifp->name);
741 else
742 vty_frame(vty, "interface %s vrf %s\n",
743 ifp->name, vrf->name);
744
91e5b43a
RW
745 if (ifp->desc)
746 vty_out(vty, " description %s\n", ifp->desc);
747
e5c83d9b
DS
748 pbr_map_write_interfaces(vty, ifp);
749
750 vty_endframe(vty, "!\n");
751 }
752 }
753
754 return 1;
755}
756
757/* PBR map node structure. */
758static struct cmd_node pbr_map_node = {PBRMAP_NODE, "%s(config-pbr-map)# ", 1};
759
760static int pbr_vty_map_config_write_sequence(struct vty *vty,
761 struct pbr_map *pbrm,
762 struct pbr_map_sequence *pbrms)
763{
764 char buff[PREFIX_STRLEN];
765
5e44f18f 766 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
e5c83d9b
DS
767
768 if (pbrms->src)
7dce96f0 769 vty_out(vty, " match src-ip %s\n",
d3765386 770 prefix2str(pbrms->src, buff, sizeof(buff)));
e5c83d9b
DS
771
772 if (pbrms->dst)
7dce96f0 773 vty_out(vty, " match dst-ip %s\n",
d3765386 774 prefix2str(pbrms->dst, buff, sizeof(buff)));
e5c83d9b 775
95a9fe02
MM
776 if (pbrms->mark)
777 vty_out(vty, " match mark %u\n", pbrms->mark);
778
be3b67b5
SW
779 if (pbrms->vrf_unchanged)
780 vty_out(vty, " set vrf unchanged\n");
781
782 if (pbrms->vrf_lookup)
783 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
784
e5c83d9b 785 if (pbrms->nhgrp_name)
7dce96f0 786 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
e5c83d9b
DS
787
788 if (pbrms->nhg) {
7dce96f0 789 vty_out(vty, " set ");
e5c83d9b
DS
790 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
791 }
792
5e44f18f 793 vty_out(vty, "!\n");
e5c83d9b
DS
794 return 1;
795}
796
797static int pbr_vty_map_config_write(struct vty *vty)
798{
799 struct pbr_map *pbrm;
800
801 pbr_nht_write_table_range(vty);
802 pbr_nht_write_rule_range(vty);
803
804 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
805 struct pbr_map_sequence *pbrms;
806 struct listnode *node;
807
d3765386 808 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
e5c83d9b 809 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
e5c83d9b
DS
810 }
811
812 return 1;
813}
814
17f8c652
DS
815static void pbr_map_completer(vector comps, struct cmd_token *token)
816{
817 struct pbr_map *pbrm;
818
819 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
820 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
821}
822
823static const struct cmd_variable_handler pbr_map_name[] = {
824 {
825 .tokenname = "PBRMAP", .completions = pbr_map_completer,
826 },
827 {
828 .completions = NULL
829 }
830};
831
e5c83d9b
DS
832void pbr_vty_init(void)
833{
17f8c652
DS
834 cmd_variable_handler_register(pbr_map_name);
835
e5c83d9b
DS
836 install_node(&interface_node,
837 pbr_interface_config_write);
838 if_cmd_init();
839
840 install_node(&pbr_map_node,
841 pbr_vty_map_config_write);
842
e14f43cc
QY
843 /* debug */
844 install_node(&debug_node, pbr_debug_config_write);
845 install_element(VIEW_NODE, &debug_pbr_cmd);
846 install_element(CONFIG_NODE, &debug_pbr_cmd);
847 install_element(VIEW_NODE, &show_debugging_pbr_cmd);
848
e5c83d9b
DS
849 install_default(PBRMAP_NODE);
850
851 install_element(CONFIG_NODE, &pbr_map_cmd);
852 install_element(CONFIG_NODE, &no_pbr_map_cmd);
7bec514c 853 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
e5c83d9b 854 install_element(INTERFACE_NODE, &pbr_policy_cmd);
e5c83d9b
DS
855 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
856 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
95a9fe02 857 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
e5c83d9b
DS
858 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
859 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
be3b67b5 860 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
e5c83d9b
DS
861 install_element(VIEW_NODE, &show_pbr_cmd);
862 install_element(VIEW_NODE, &show_pbr_map_cmd);
863 install_element(VIEW_NODE, &show_pbr_interface_cmd);
864 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
e5c83d9b 865}