]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_vty.c
doc: document json for remaining `show pbr` cmds
[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"
7a7b0c13 30#include "json.h"
e5c83d9b 31#include "debug.h"
8c28c034 32#include "pbr.h"
e5c83d9b
DS
33
34#include "pbrd/pbr_nht.h"
35#include "pbrd/pbr_map.h"
36#include "pbrd/pbr_zebra.h"
37#include "pbrd/pbr_vty.h"
e5c83d9b
DS
38#include "pbrd/pbr_debug.h"
39#ifndef VTYSH_EXTRACT_PL
40#include "pbrd/pbr_vty_clippy.c"
41#endif
42
17f8c652 43DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
e5c83d9b
DS
44 "Create pbr-map or enter pbr-map command mode\n"
45 "The name of the PBR MAP\n"
46 "Sequence to insert in existing pbr-map entry\n"
47 "Sequence number\n")
48{
49 const char *pbrm_name = argv[1]->arg;
50 uint32_t seqno = atoi(argv[3]->arg);
51 struct pbr_map_sequence *pbrms;
52
53 pbrms = pbrms_get(pbrm_name, seqno);
54 VTY_PUSH_CONTEXT(PBRMAP_NODE, pbrms);
55
56 return CMD_SUCCESS;
57}
58
17f8c652 59DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
e5c83d9b
DS
60 NO_STR
61 "Delete pbr-map\n"
62 "The name of the PBR MAP\n"
63 "Sequence to delete from existing pbr-map entry\n"
64 "Sequence number\n")
65{
66 const char *pbrm_name = argv[2]->arg;
67 uint32_t seqno = 0;
68 struct pbr_map *pbrm = pbrm_find(pbrm_name);
e5c83d9b
DS
69 struct pbr_map_sequence *pbrms;
70 struct listnode *node, *next_node;
71
72 if (argc > 3)
73 seqno = atoi(argv[4]->arg);
74
75 if (!pbrm) {
76 vty_out(vty, "pbr-map %s not found\n", pbrm_name);
77 return CMD_SUCCESS;
78 }
79
b13e5ad6
DS
80 for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, next_node, pbrms)) {
81 if (seqno && pbrms->seqno != seqno)
82 continue;
e5c83d9b 83
b13e5ad6
DS
84 pbr_map_delete(pbrms);
85 }
e5c83d9b
DS
86
87 return CMD_SUCCESS;
88}
89
7bec514c
QY
90DEFPY(pbr_set_table_range,
91 pbr_set_table_range_cmd,
b246eb8a 92 "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
7bec514c
QY
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
b246eb8a
SW
116DEFPY(no_pbr_set_table_range, no_pbr_set_table_range_cmd,
117 "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
118 NO_STR
119 PBR_STR
120 "Set table ID range\n"
121 "Set table ID range\n"
122 "Lower bound for table ID range\n"
123 "Upper bound for table ID range\n")
124{
125 pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
126 PBR_NHT_DEFAULT_HIGH_TABLEID);
127 return CMD_SUCCESS;
128}
7bec514c 129
e5c83d9b
DS
130DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
131 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
132 NO_STR
133 "Match the rest of the command\n"
134 "Choose the src ip or ipv6 prefix to use\n"
135 "v4 Prefix\n"
136 "v6 Prefix\n")
137{
138 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b 139
49027ce8
DS
140 pbrms->family = prefix->family;
141
e5c83d9b 142 if (!no) {
5d0e49c4
SW
143 if (pbrms->src) {
144 if (prefix_same(pbrms->src, prefix))
145 return CMD_SUCCESS;
f143cffa
SW
146 } else
147 pbrms->src = prefix_new();
5d0e49c4 148
e5c83d9b 149 prefix_copy(pbrms->src, prefix);
63265b5c
DS
150 } else
151 prefix_free(&pbrms->src);
e5c83d9b 152
f143cffa 153 pbr_map_check(pbrms, true);
e5c83d9b
DS
154
155 return CMD_SUCCESS;
156}
157
158DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
159 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
160 NO_STR
161 "Match the rest of the command\n"
6c4c9a6c 162 "Choose the dst ip or ipv6 prefix to use\n"
e5c83d9b
DS
163 "v4 Prefix\n"
164 "v6 Prefix\n")
165{
166 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b 167
49027ce8
DS
168 pbrms->family = prefix->family;
169
e5c83d9b 170 if (!no) {
5d0e49c4
SW
171 if (pbrms->dst) {
172 if (prefix_same(pbrms->dst, prefix))
173 return CMD_SUCCESS;
f143cffa
SW
174 } else
175 pbrms->dst = prefix_new();
5d0e49c4 176
e5c83d9b 177 prefix_copy(pbrms->dst, prefix);
63265b5c
DS
178 } else
179 prefix_free(&pbrms->dst);
e5c83d9b 180
f143cffa 181 pbr_map_check(pbrms, true);
e5c83d9b
DS
182
183 return CMD_SUCCESS;
184}
185
95a9fe02
MM
186DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
187 "[no] match mark (1-4294967295)$mark",
188 NO_STR
189 "Match the rest of the command\n"
190 "Choose the mark value to use\n"
191 "mark\n")
192{
193 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
194
195#ifndef GNU_LINUX
196 vty_out(vty, "pbr marks are not supported on this platform");
197 return CMD_WARNING_CONFIG_FAILED;
198#endif
199
200 if (!no) {
f143cffa 201 if (pbrms->mark)
5d0e49c4
SW
202 if (pbrms->mark == (uint32_t)mark)
203 return CMD_SUCCESS;
204
5d0e49c4
SW
205 pbrms->mark = (uint32_t)mark;
206 } else
95a9fe02 207 pbrms->mark = 0;
95a9fe02 208
f143cffa 209 pbr_map_check(pbrms, true);
95a9fe02
MM
210
211 return CMD_SUCCESS;
be3b67b5
SW
212}
213
f143cffa
SW
214static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
215{
216 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
217 pbr_map_delete_vrf(pbrms);
218 pbrms->vrf_name[0] = '\0';
219 pbrms->vrf_lookup = false;
220 pbrms->vrf_unchanged = false;
221 }
222}
223
224static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
225{
226 if (pbrms->nhgrp_name)
227 pbr_map_delete_nexthops(pbrms);
228}
229
230static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
231{
232 if (pbrms->nhg)
233 pbr_nht_delete_individual_nexthop(pbrms);
234}
235
236static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
237{
238 pbrms_clear_set_vrf_config(pbrms);
239 pbrms_clear_set_nhg_config(pbrms);
240 pbrms_clear_set_nexthop_config(pbrms);
241
242 pbrms->nhs_installed = false;
243}
95a9fe02 244
e5c83d9b 245DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
bce03323 246 "set nexthop-group NHGNAME$name",
be3b67b5
SW
247 "Set for the PBR-MAP\n"
248 "nexthop-group to use\n"
249 "The name of the nexthop-group\n")
e5c83d9b
DS
250{
251 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
252 struct nexthop_group_cmd *nhgc;
e5c83d9b
DS
253
254 nhgc = nhgc_find(name);
255 if (!nhgc) {
256 vty_out(vty, "Specified nexthop-group %s does not exist\n",
257 name);
be3b67b5
SW
258 vty_out(vty,
259 "PBR-MAP will not be applied until it is created\n");
e5c83d9b
DS
260 }
261
f143cffa
SW
262 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
263 return CMD_SUCCESS;
264
265 /* This is new/replacement config */
266 pbrms_clear_set_config(pbrms);
267
268 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
269 pbr_map_check(pbrms, true);
270
e5c83d9b
DS
271 return CMD_SUCCESS;
272}
273
bce03323
SW
274DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
275 "no set nexthop-group [NHGNAME$name]",
276 NO_STR
277 "Set for the PBR-MAP\n"
278 "nexthop-group to use\n"
279 "The name of the nexthop-group\n")
280{
281 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
282
283 pbrms_clear_set_config(pbrms);
284
285 return CMD_SUCCESS;
286}
287
e5c83d9b 288DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
bce03323 289 "set nexthop\
9c0fd853
RW
290 <\
291 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
292 |INTERFACE$intf\
293 >\
e429a2a0 294 [nexthop-vrf NAME$vrf_name]",
e5c83d9b
DS
295 "Set for the PBR-MAP\n"
296 "Specify one of the nexthops in this map\n"
297 "v4 Address\n"
298 "v6 Address\n"
299 "Interface to use\n"
9c0fd853 300 "Interface to use\n"
e5c83d9b
DS
301 "If the nexthop is in a different vrf tell us\n"
302 "The nexthop-vrf Name\n")
303{
304 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
305 struct vrf *vrf;
306 struct nexthop nhop;
f143cffa 307 struct nexthop *nh = NULL;
be3b67b5 308
e429a2a0
IR
309 if (vrf_name)
310 vrf = vrf_lookup_by_name(vrf_name);
e5c83d9b
DS
311 else
312 vrf = vrf_lookup_by_id(VRF_DEFAULT);
313
314 if (!vrf) {
e429a2a0 315 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
3a9210c2 316 return CMD_WARNING_CONFIG_FAILED;
e5c83d9b
DS
317 }
318
319 memset(&nhop, 0, sizeof(nhop));
320 nhop.vrf_id = vrf->vrf_id;
321
9c0fd853
RW
322 if (intf) {
323 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
324 if (nhop.ifindex == IFINDEX_INTERNAL) {
325 vty_out(vty,
326 "Specified Intf %s does not exist in vrf: %s\n",
327 intf, vrf->name);
328 return CMD_WARNING_CONFIG_FAILED;
329 }
330 }
331
332 if (addr) {
333 if (addr->sa.sa_family == AF_INET) {
334 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
335 if (intf)
336 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
337 else
338 nhop.type = NEXTHOP_TYPE_IPV4;
cafec8da 339 } else {
9c0fd853
RW
340 nhop.gate.ipv6 = addr->sin6.sin6_addr;
341 if (intf)
342 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
343 else {
344 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
345 vty_out(vty,
346 "Specified a v6 LL with no interface, rejecting\n");
347 return CMD_WARNING_CONFIG_FAILED;
348 }
349 nhop.type = NEXTHOP_TYPE_IPV6;
cafec8da 350 }
cafec8da 351 }
9c0fd853
RW
352 } else
353 nhop.type = NEXTHOP_TYPE_IFINDEX;
e5c83d9b
DS
354
355 if (pbrms->nhg)
356 nh = nexthop_exists(pbrms->nhg, &nhop);
e5c83d9b 357
f143cffa
SW
358 if (nh) /* Same config re-entered */
359 goto done;
e5c83d9b 360
f143cffa
SW
361 /* This is new/replacement config */
362 pbrms_clear_set_config(pbrms);
e5c83d9b 363
f143cffa 364 pbr_nht_add_individual_nexthop(pbrms, &nhop);
e5c83d9b 365
f143cffa 366 pbr_map_check(pbrms, true);
e5c83d9b 367
f143cffa 368done:
cb254f41
SW
369 if (nhop.type == NEXTHOP_TYPE_IFINDEX
370 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
371 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
9c0fd853
RW
372 struct interface *ifp;
373
374 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
375 if (ifp)
376 pbr_nht_nexthop_interface_update(ifp);
377 }
378
e5c83d9b
DS
379 return CMD_SUCCESS;
380}
381
bce03323
SW
382DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
383 "no set nexthop\
384 [<\
385 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
386 |INTERFACE$intf\
387 >\
388 [nexthop-vrf NAME$vrf_name]]",
be3b67b5
SW
389 NO_STR
390 "Set for the PBR-MAP\n"
bce03323
SW
391 "Specify one of the nexthops in this map\n"
392 "v4 Address\n"
393 "v6 Address\n"
394 "Interface to use\n"
395 "Interface to use\n"
396 "If the nexthop is in a different vrf tell us\n"
397 "The nexthop-vrf Name\n")
398{
399 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
400
401 pbrms_clear_set_config(pbrms);
402
403 return CMD_SUCCESS;
404}
405
406DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
407 "set vrf <NAME$vrf_name|unchanged>",
408 "Set for the PBR-MAP\n"
be3b67b5
SW
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);
be3b67b5 414
9bf1b0f7 415 /*
f143cffa 416 * If an equivalent set vrf * exists, just return success.
9bf1b0f7 417 */
f143cffa
SW
418 if (vrf_name && pbrms->vrf_lookup
419 && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0)
f3f2c78a 420 return CMD_SUCCESS;
f143cffa 421 else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */
f3f2c78a 422 return CMD_SUCCESS;
9bf1b0f7 423
bce03323
SW
424 if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) {
425 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
426 return CMD_WARNING_CONFIG_FAILED;
427 }
428
f143cffa
SW
429 /* This is new/replacement config */
430 pbrms_clear_set_config(pbrms);
be3b67b5
SW
431
432 if (vrf_name) {
be3b67b5
SW
433 pbrms->vrf_lookup = true;
434 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
435 } else
436 pbrms->vrf_unchanged = true;
437
f143cffa 438 pbr_map_check(pbrms, true);
be3b67b5 439
f3f2c78a 440 return CMD_SUCCESS;
be3b67b5
SW
441}
442
bce03323
SW
443DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
444 "no set vrf [<NAME$vrf_name|unchanged>]",
445 NO_STR
446 "Set for the PBR-MAP\n"
447 "Specify the VRF for this map\n"
448 "The VRF Name\n"
449 "Use the interface's VRF for lookup\n")
450{
451 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
452
453 pbrms_clear_set_config(pbrms);
454
455 return CMD_SUCCESS;
456}
457
e5c83d9b
DS
458DEFPY (pbr_policy,
459 pbr_policy_cmd,
17f8c652 460 "[no] pbr-policy PBRMAP$mapname",
e5c83d9b
DS
461 NO_STR
462 "Policy to use\n"
463 "Name of the pbr-map to apply\n")
464{
465 VTY_DECLVAR_CONTEXT(interface, ifp);
466 struct pbr_map *pbrm, *old_pbrm;
467 struct pbr_interface *pbr_ifp = ifp->info;
468
6eb499b0 469 old_pbrm = NULL;
e5c83d9b
DS
470 pbrm = pbrm_find(mapname);
471
b13e5ad6 472 if (!pbr_ifp) {
d6416967
QY
473 /* we don't want one and we don't have one, so... */
474 if (no)
475 return CMD_SUCCESS;
476
477 /* Some one could have fat fingered the interface name */
b13e5ad6
DS
478 pbr_ifp = pbr_if_new(ifp);
479 }
480
e5c83d9b
DS
481 if (no) {
482 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
5f504f14 483 pbr_ifp->mapname[0] = '\0';
e5c83d9b
DS
484 if (pbrm)
485 pbr_map_interface_delete(pbrm, ifp);
486 }
487 } else {
5f504f14
QY
488 if (strcmp(pbr_ifp->mapname, "") != 0) {
489 old_pbrm = pbrm_find(pbr_ifp->mapname);
6eb499b0
DS
490
491 /*
492 * So if we have an old pbrm we should only
493 * delete it if we are actually deleting and
494 * moving to a new pbrm
495 */
496 if (old_pbrm && old_pbrm != pbrm)
5f504f14 497 pbr_map_interface_delete(old_pbrm, ifp);
e5c83d9b 498 }
5f504f14
QY
499 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
500 "%s", mapname);
6eb499b0
DS
501
502 /*
503 * So only reinstall if the old_pbrm and this pbrm are
504 * different.
505 */
506 if (pbrm && pbrm != old_pbrm)
5f504f14 507 pbr_map_add_interface(pbrm, ifp);
e5c83d9b
DS
508 }
509
510 return CMD_SUCCESS;
511}
512
513DEFPY (show_pbr,
514 show_pbr_cmd,
ef18ed6e 515 "show pbr",
e5c83d9b 516 SHOW_STR
24a21176 517 PBR_STR)
e5c83d9b
DS
518{
519 pbr_nht_write_table_range(vty);
520 pbr_nht_write_rule_range(vty);
521
522 return CMD_SUCCESS;
523}
524
1eaa8361
SW
525static void vty_show_pbrms(struct vty *vty,
526 const struct pbr_map_sequence *pbrms, bool detail)
527{
528 char buf[PREFIX_STRLEN];
529 char rbuf[64];
530
531 if (pbrms->reason)
532 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
3259cde6
SW
533
534 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
535
536 if (detail)
b740126d 537 vty_out(vty, " Installed: %" PRIu64 "(%u) Reason: %s\n",
3259cde6
SW
538 pbrms->installed, pbrms->unique,
539 pbrms->reason ? rbuf : "Valid");
540 else
b740126d 541 vty_out(vty, " Installed: %s Reason: %s\n",
3259cde6
SW
542 pbrms->installed ? "yes" : "no",
543 pbrms->reason ? rbuf : "Valid");
1eaa8361
SW
544
545 if (pbrms->src)
b740126d 546 vty_out(vty, " SRC Match: %s\n",
1eaa8361
SW
547 prefix2str(pbrms->src, buf, sizeof(buf)));
548 if (pbrms->dst)
b740126d 549 vty_out(vty, " DST Match: %s\n",
1eaa8361
SW
550 prefix2str(pbrms->dst, buf, sizeof(buf)));
551 if (pbrms->mark)
b740126d 552 vty_out(vty, " MARK Match: %u\n", pbrms->mark);
1eaa8361
SW
553
554 if (pbrms->nhgrp_name) {
b740126d 555 vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
add5e0a4 556
3259cde6 557 if (detail)
b740126d
SW
558 vty_out(vty,
559 " Installed: %u(%d) Tableid: %d\n",
3259cde6 560 pbrms->nhs_installed,
add5e0a4
SW
561 pbr_nht_get_installed(pbrms->nhgrp_name),
562 pbr_nht_get_table(pbrms->nhgrp_name));
3259cde6 563 else
b740126d 564 vty_out(vty, " Installed: %s Tableid: %d\n",
add5e0a4
SW
565 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
566 : "no",
567 pbr_nht_get_table(pbrms->nhgrp_name));
568
1eaa8361 569 } else if (pbrms->nhg) {
b740126d 570 vty_out(vty, " ");
1eaa8361 571 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
3259cde6 572 if (detail)
b740126d
SW
573 vty_out(vty,
574 " Installed: %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
b740126d 579 vty_out(vty, " Installed: %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 585 } else if (pbrms->vrf_unchanged) {
b740126d 586 vty_out(vty, " VRF Unchanged (use interface vrf)\n");
1eaa8361 587 } else if (pbrms->vrf_lookup) {
b740126d 588 vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name);
1eaa8361 589 } else {
b740126d 590 vty_out(vty, " Nexthop-Group: Unknown Installed: no\n");
1eaa8361
SW
591 }
592}
593
1a8cafe1
WC
594static void vty_json_pbrms(json_object *j, struct vty *vty,
595 const struct pbr_map_sequence *pbrms)
596{
81c0078e 597 json_object *jpbrm, *nexthop_group;
1a8cafe1
WC
598 char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
599 : pbrms->internal_nhg_name;
600 char buf[PREFIX_STRLEN];
601 char rbuf[64];
602
603 jpbrm = json_object_new_object();
604
81c0078e
WC
605 json_object_int_add(jpbrm, "id", pbrms->unique);
606
1a8cafe1
WC
607 if (pbrms->reason)
608 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
609
610 json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
611 json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
1a8cafe1 612 json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
81c0078e 613 json_object_boolean_add(jpbrm, "isInstalled",
1a8cafe1 614 pbr_nht_get_installed(nhg_name));
81c0078e
WC
615 json_object_string_add(jpbrm, "installedReason",
616 pbrms->reason ? rbuf : "Valid");
1a8cafe1 617
81c0078e 618 if (nhg_name) {
1a8cafe1
WC
619 nexthop_group = json_object_new_object();
620
81c0078e 621 json_object_int_add(nexthop_group, "id",
1a8cafe1 622 pbr_nht_get_table(nhg_name));
81c0078e
WC
623 json_object_string_add(nexthop_group, "name", nhg_name);
624 json_object_boolean_add(nexthop_group, "isInstalled",
1a8cafe1 625 pbr_nht_get_installed(nhg_name));
81c0078e
WC
626 json_object_int_add(nexthop_group, "isInstalledInternally",
627 pbrms->nhs_installed);
1a8cafe1
WC
628
629 json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
1a8cafe1
WC
630 }
631
81c0078e
WC
632 if (pbrms->vrf_lookup)
633 json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
1a8cafe1 634
81c0078e
WC
635 if (pbrms->src)
636 json_object_string_add(
637 jpbrm, "matchSrc",
638 prefix2str(pbrms->src, buf, sizeof(buf)));
639 if (pbrms->dst)
640 json_object_string_add(
641 jpbrm, "matchDst",
642 prefix2str(pbrms->dst, buf, sizeof(buf)));
643 if (pbrms->mark)
644 json_object_int_add(jpbrm, "matchMark", pbrms->mark);
1a8cafe1
WC
645
646 json_object_array_add(j, jpbrm);
647}
648
1eaa8361
SW
649static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
650 bool detail)
651{
652 struct pbr_map_sequence *pbrms;
653 struct listnode *node;
654
1ce24b9b
SW
655 vty_out(vty, " pbr-map %s valid: %s\n", pbrm->name,
656 pbrm->valid ? "yes" : "no");
1eaa8361
SW
657
658 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
659 vty_show_pbrms(vty, pbrms, detail);
660}
661
1a8cafe1
WC
662static void vty_json_pbr_map(json_object *j, struct vty *vty,
663 const struct pbr_map *pbrm)
664{
665 struct pbr_map_sequence *pbrms;
666 struct listnode *node;
667 json_object *jpbrms;
668
669 json_object_string_add(j, "name", pbrm->name);
81c0078e 670 json_object_boolean_add(j, "isValid", pbrm->valid);
1a8cafe1
WC
671
672 jpbrms = json_object_new_array();
673
674 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
675 vty_json_pbrms(jpbrms, vty, pbrms);
676
677 json_object_object_add(j, "sequences", jpbrms);
678}
679
e5c83d9b
DS
680DEFPY (show_pbr_map,
681 show_pbr_map_cmd,
1a8cafe1 682 "show pbr map [NAME$name] [detail$detail|json$json]",
e5c83d9b 683 SHOW_STR
24a21176 684 PBR_STR
e5c83d9b
DS
685 "PBR Map\n"
686 "PBR Map Name\n"
1a8cafe1
WC
687 "Detailed information\n"
688 JSON_STR)
e5c83d9b 689{
e5c83d9b 690 struct pbr_map *pbrm;
1a8cafe1
WC
691 json_object *j = NULL;
692
693 if (json)
dadba1a2 694 j = json_object_new_array();
e5c83d9b
DS
695
696 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
1a8cafe1 697 json_object *this_map = NULL;
e5c83d9b
DS
698 if (name && strcmp(name, pbrm->name) != 0)
699 continue;
700
1a8cafe1
WC
701 if (j)
702 this_map = json_object_new_object();
703
704 if (this_map) {
705 vty_json_pbr_map(this_map, vty, pbrm);
706
dadba1a2 707 json_object_array_add(j, this_map);
1a8cafe1
WC
708 continue;
709 }
710
1eaa8361 711 vty_show_pbr_map(vty, pbrm, detail);
e5c83d9b 712 }
1a8cafe1
WC
713
714 if (j) {
715 vty_out(vty, "%s\n",
716 json_object_to_json_string_ext(
717 j, JSON_C_TO_STRING_PRETTY));
718 json_object_free(j);
719 }
720
e5c83d9b
DS
721 return CMD_SUCCESS;
722}
723
724DEFPY(show_pbr_nexthop_group,
725 show_pbr_nexthop_group_cmd,
010dd8ed 726 "show pbr nexthop-groups [WORD$word] [json$json]",
e5c83d9b 727 SHOW_STR
24a21176 728 PBR_STR
e5c83d9b 729 "Nexthop Groups\n"
010dd8ed
WC
730 "Optional Name of the nexthop group\n"
731 JSON_STR)
e5c83d9b 732{
010dd8ed
WC
733 json_object *j = NULL;
734
735 if (json)
dadba1a2 736 j = json_object_new_array();
010dd8ed
WC
737
738 if (j) {
739 pbr_nht_json_nexthop_group(j, word);
740
741 vty_out(vty, "%s\n",
742 json_object_to_json_string_ext(
743 j, JSON_C_TO_STRING_PRETTY));
744
745 json_object_free(j);
746 } else
747 pbr_nht_show_nexthop_group(vty, word);
748
e5c83d9b
DS
749
750 return CMD_SUCCESS;
751}
752
753DEFPY (show_pbr_interface,
754 show_pbr_interface_cmd,
7a7b0c13 755 "show pbr interface [NAME$name] [json$json]",
e5c83d9b 756 SHOW_STR
24a21176 757 PBR_STR
e5c83d9b 758 "PBR Interface\n"
7a7b0c13
WC
759 "PBR Interface Name\n"
760 JSON_STR)
e5c83d9b 761{
d3765386 762 struct interface *ifp;
e5c83d9b
DS
763 struct vrf *vrf;
764 struct pbr_interface *pbr_ifp;
7a7b0c13
WC
765 json_object *j = NULL;
766
767 if (json)
dadba1a2 768 j = json_object_new_array();
e5c83d9b
DS
769
770 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
771 FOR_ALL_INTERFACES(vrf, ifp) {
772 struct pbr_map *pbrm;
7a7b0c13
WC
773 json_object *this_iface = NULL;
774
775 if (j)
776 this_iface = json_object_new_object();
e5c83d9b 777
1c33fb1d
DS
778 if (!ifp->info)
779 continue;
780
e5c83d9b
DS
781 if (name && strcmp(ifp->name, name) != 0)
782 continue;
783
784 pbr_ifp = ifp->info;
785
786 if (strcmp(pbr_ifp->mapname, "") == 0)
787 continue;
788
789 pbrm = pbrm_find(pbr_ifp->mapname);
7a7b0c13
WC
790
791 if (this_iface) {
792 json_object_string_add(this_iface, "name",
793 ifp->name);
794 json_object_int_add(this_iface, "index",
795 ifp->ifindex);
796 json_object_string_add(this_iface, "policy",
797 pbr_ifp->mapname);
81c0078e 798 json_object_boolean_add(this_iface, "isValid",
7a7b0c13
WC
799 pbrm);
800
dadba1a2 801 json_object_array_add(j, this_iface);
7a7b0c13
WC
802 continue;
803 }
804
e5c83d9b
DS
805 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
806 ifp->ifindex, pbr_ifp->mapname);
807 if (!pbrm)
808 vty_out(vty, " (map doesn't exist)");
809 vty_out(vty, "\n");
810 }
811 }
812
7a7b0c13
WC
813 if (j) {
814 vty_out(vty, "%s\n",
815 json_object_to_json_string_ext(
816 j, JSON_C_TO_STRING_PRETTY));
817 json_object_free(j);
818 }
819
e5c83d9b
DS
820 return CMD_SUCCESS;
821}
822
e14f43cc 823/* PBR debugging CLI ------------------------------------------------------- */
e14f43cc 824
62b346ee 825static struct cmd_node debug_node = {
f4b8291f 826 .name = "debug",
62b346ee
DL
827 .node = DEBUG_NODE,
828 .prompt = "",
612c2c15 829 .config_write = pbr_debug_config_write,
62b346ee 830};
e14f43cc
QY
831
832DEFPY(debug_pbr,
833 debug_pbr_cmd,
834 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
835 NO_STR
836 DEBUG_STR
24a21176 837 PBR_STR
e14f43cc
QY
838 "Policy maps\n"
839 "PBRD <-> Zebra communications\n"
840 "Nexthop tracking\n"
841 "Events\n")
842{
843 uint32_t mode = DEBUG_NODE2MODE(vty->node);
844
845 if (map)
846 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
847 if (zebra)
848 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
849 if (nht)
850 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
851 if (events)
852 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
853
854 /* no specific debug --> act on all of them */
855 if (strmatch(argv[argc - 1]->text, "pbr"))
856 pbr_debug_set_all(mode, !no);
857
858 return CMD_SUCCESS;
859}
860
861DEFUN_NOSH(show_debugging_pbr,
862 show_debugging_pbr_cmd,
863 "show debugging [pbr]",
864 SHOW_STR
865 DEBUG_STR
24a21176 866 PBR_STR)
e14f43cc
QY
867{
868 vty_out(vty, "PBR debugging status:\n");
869
870 pbr_debug_config_write_helper(vty, false);
871
872 return CMD_SUCCESS;
873}
874
e14f43cc
QY
875/* ------------------------------------------------------------------------- */
876
877
612c2c15 878static int pbr_interface_config_write(struct vty *vty);
e5c83d9b 879static struct cmd_node interface_node = {
f4b8291f 880 .name = "interface",
62b346ee 881 .node = INTERFACE_NODE,
24389580 882 .parent_node = CONFIG_NODE,
62b346ee 883 .prompt = "%s(config-if)# ",
612c2c15 884 .config_write = pbr_interface_config_write,
e5c83d9b
DS
885};
886
887static int pbr_interface_config_write(struct vty *vty)
888{
889 struct interface *ifp;
890 struct vrf *vrf;
891
892 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
893 FOR_ALL_INTERFACES (vrf, ifp) {
894 if (vrf->vrf_id == VRF_DEFAULT)
895 vty_frame(vty, "interface %s\n", ifp->name);
896 else
897 vty_frame(vty, "interface %s vrf %s\n",
898 ifp->name, vrf->name);
899
91e5b43a
RW
900 if (ifp->desc)
901 vty_out(vty, " description %s\n", ifp->desc);
902
e5c83d9b
DS
903 pbr_map_write_interfaces(vty, ifp);
904
905 vty_endframe(vty, "!\n");
906 }
907 }
908
909 return 1;
910}
911
612c2c15 912static int pbr_vty_map_config_write(struct vty *vty);
e5c83d9b 913/* PBR map node structure. */
62b346ee 914static struct cmd_node pbr_map_node = {
f4b8291f 915 .name = "pbr-map",
62b346ee 916 .node = PBRMAP_NODE,
24389580 917 .parent_node = CONFIG_NODE,
62b346ee 918 .prompt = "%s(config-pbr-map)# ",
612c2c15 919 .config_write = pbr_vty_map_config_write,
62b346ee 920};
e5c83d9b
DS
921
922static int pbr_vty_map_config_write_sequence(struct vty *vty,
923 struct pbr_map *pbrm,
924 struct pbr_map_sequence *pbrms)
925{
926 char buff[PREFIX_STRLEN];
927
5e44f18f 928 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
e5c83d9b
DS
929
930 if (pbrms->src)
7dce96f0 931 vty_out(vty, " match src-ip %s\n",
d3765386 932 prefix2str(pbrms->src, buff, sizeof(buff)));
e5c83d9b
DS
933
934 if (pbrms->dst)
7dce96f0 935 vty_out(vty, " match dst-ip %s\n",
d3765386 936 prefix2str(pbrms->dst, buff, sizeof(buff)));
e5c83d9b 937
95a9fe02
MM
938 if (pbrms->mark)
939 vty_out(vty, " match mark %u\n", pbrms->mark);
940
be3b67b5
SW
941 if (pbrms->vrf_unchanged)
942 vty_out(vty, " set vrf unchanged\n");
943
944 if (pbrms->vrf_lookup)
945 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
946
e5c83d9b 947 if (pbrms->nhgrp_name)
7dce96f0 948 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
e5c83d9b
DS
949
950 if (pbrms->nhg) {
7dce96f0 951 vty_out(vty, " set ");
e5c83d9b
DS
952 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
953 }
954
5e44f18f 955 vty_out(vty, "!\n");
e5c83d9b
DS
956 return 1;
957}
958
959static int pbr_vty_map_config_write(struct vty *vty)
960{
961 struct pbr_map *pbrm;
962
963 pbr_nht_write_table_range(vty);
964 pbr_nht_write_rule_range(vty);
965
966 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
967 struct pbr_map_sequence *pbrms;
968 struct listnode *node;
969
d3765386 970 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
e5c83d9b 971 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
e5c83d9b
DS
972 }
973
974 return 1;
975}
976
17f8c652
DS
977static void pbr_map_completer(vector comps, struct cmd_token *token)
978{
979 struct pbr_map *pbrm;
980
981 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
982 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
983}
984
985static const struct cmd_variable_handler pbr_map_name[] = {
986 {
987 .tokenname = "PBRMAP", .completions = pbr_map_completer,
988 },
989 {
990 .completions = NULL
991 }
992};
993
e5c83d9b
DS
994void pbr_vty_init(void)
995{
17f8c652
DS
996 cmd_variable_handler_register(pbr_map_name);
997
612c2c15 998 install_node(&interface_node);
e5c83d9b
DS
999 if_cmd_init();
1000
612c2c15 1001 install_node(&pbr_map_node);
e5c83d9b 1002
e14f43cc 1003 /* debug */
612c2c15 1004 install_node(&debug_node);
e14f43cc
QY
1005 install_element(VIEW_NODE, &debug_pbr_cmd);
1006 install_element(CONFIG_NODE, &debug_pbr_cmd);
1007 install_element(VIEW_NODE, &show_debugging_pbr_cmd);
1008
e5c83d9b
DS
1009 install_default(PBRMAP_NODE);
1010
1011 install_element(CONFIG_NODE, &pbr_map_cmd);
1012 install_element(CONFIG_NODE, &no_pbr_map_cmd);
7bec514c 1013 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
b246eb8a 1014 install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);
e5c83d9b 1015 install_element(INTERFACE_NODE, &pbr_policy_cmd);
e5c83d9b
DS
1016 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
1017 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
95a9fe02 1018 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
e5c83d9b 1019 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
bce03323 1020 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
e5c83d9b 1021 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
bce03323 1022 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_cmd);
be3b67b5 1023 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
bce03323 1024 install_element(PBRMAP_NODE, &no_pbr_map_vrf_cmd);
e5c83d9b
DS
1025 install_element(VIEW_NODE, &show_pbr_cmd);
1026 install_element(VIEW_NODE, &show_pbr_map_cmd);
1027 install_element(VIEW_NODE, &show_pbr_interface_cmd);
1028 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
e5c83d9b 1029}