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