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