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