]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_vty.c
build, vtysh: extract vtysh commands from .xref
[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 38#include "pbrd/pbr_debug.h"
e5c83d9b 39#include "pbrd/pbr_vty_clippy.c"
e5c83d9b 40
17f8c652 41DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
e5c83d9b
DS
42 "Create pbr-map or enter pbr-map command mode\n"
43 "The name of the PBR MAP\n"
44 "Sequence to insert in existing pbr-map entry\n"
45 "Sequence number\n")
46{
47 const char *pbrm_name = argv[1]->arg;
48 uint32_t seqno = atoi(argv[3]->arg);
49 struct pbr_map_sequence *pbrms;
50
51 pbrms = pbrms_get(pbrm_name, seqno);
52 VTY_PUSH_CONTEXT(PBRMAP_NODE, pbrms);
53
54 return CMD_SUCCESS;
55}
56
17f8c652 57DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
e5c83d9b
DS
58 NO_STR
59 "Delete pbr-map\n"
60 "The name of the PBR MAP\n"
61 "Sequence to delete from existing pbr-map entry\n"
62 "Sequence number\n")
63{
64 const char *pbrm_name = argv[2]->arg;
65 uint32_t seqno = 0;
66 struct pbr_map *pbrm = pbrm_find(pbrm_name);
e5c83d9b
DS
67 struct pbr_map_sequence *pbrms;
68 struct listnode *node, *next_node;
69
70 if (argc > 3)
71 seqno = atoi(argv[4]->arg);
72
73 if (!pbrm) {
74 vty_out(vty, "pbr-map %s not found\n", pbrm_name);
75 return CMD_SUCCESS;
76 }
77
b13e5ad6
DS
78 for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, next_node, pbrms)) {
79 if (seqno && pbrms->seqno != seqno)
80 continue;
e5c83d9b 81
b13e5ad6
DS
82 pbr_map_delete(pbrms);
83 }
e5c83d9b
DS
84
85 return CMD_SUCCESS;
86}
87
7bec514c
QY
88DEFPY(pbr_set_table_range,
89 pbr_set_table_range_cmd,
b246eb8a 90 "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub",
7bec514c
QY
91 PBR_STR
92 "Set table ID range\n"
93 "Set table ID range\n"
94 "Lower bound for table ID range\n"
95 "Upper bound for table ID range\n")
96{
97 /* upper bound is 2^32 - 2^10 */
98 int ret = CMD_WARNING;
a4044dc1 99 const int minrange = 1000;
7bec514c
QY
100
101 /* validate given bounds */
102 if (lb > ub)
103 vty_out(vty, "%% Lower bound must be less than upper bound\n");
a4044dc1
QY
104 else if (ub - lb < minrange)
105 vty_out(vty, "%% Range breadth must be at least %d\n", minrange);
7bec514c
QY
106 else {
107 ret = CMD_SUCCESS;
108 pbr_nht_set_tableid_range((uint32_t) lb, (uint32_t) ub);
109 }
110
111 return ret;
112}
113
b246eb8a
SW
114DEFPY(no_pbr_set_table_range, no_pbr_set_table_range_cmd,
115 "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]",
116 NO_STR
117 PBR_STR
118 "Set table ID range\n"
119 "Set table ID range\n"
120 "Lower bound for table ID range\n"
121 "Upper bound for table ID range\n")
122{
123 pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
124 PBR_NHT_DEFAULT_HIGH_TABLEID);
125 return CMD_SUCCESS;
126}
7bec514c 127
e5c83d9b
DS
128DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
129 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
130 NO_STR
131 "Match the rest of the command\n"
132 "Choose the src ip or ipv6 prefix to use\n"
133 "v4 Prefix\n"
134 "v6 Prefix\n")
135{
136 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b 137
70219836
DS
138 if (!pbrms)
139 return CMD_WARNING_CONFIG_FAILED;
140
67765a23
SW
141 if (pbrms->dst && pbrms->family && prefix->family != pbrms->family) {
142 vty_out(vty, "Cannot mismatch families within match src/dst\n");
143 return CMD_WARNING_CONFIG_FAILED;
144 }
145
49027ce8
DS
146 pbrms->family = prefix->family;
147
e5c83d9b 148 if (!no) {
5d0e49c4
SW
149 if (pbrms->src) {
150 if (prefix_same(pbrms->src, prefix))
151 return CMD_SUCCESS;
f143cffa
SW
152 } else
153 pbrms->src = prefix_new();
5d0e49c4 154
e5c83d9b 155 prefix_copy(pbrms->src, prefix);
63265b5c
DS
156 } else
157 prefix_free(&pbrms->src);
e5c83d9b 158
f143cffa 159 pbr_map_check(pbrms, true);
e5c83d9b
DS
160
161 return CMD_SUCCESS;
162}
163
164DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
165 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
166 NO_STR
167 "Match the rest of the command\n"
6c4c9a6c 168 "Choose the dst ip or ipv6 prefix to use\n"
e5c83d9b
DS
169 "v4 Prefix\n"
170 "v6 Prefix\n")
171{
172 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b 173
70219836
DS
174 if (!pbrms)
175 return CMD_WARNING_CONFIG_FAILED;
176
67765a23
SW
177 if (pbrms->src && pbrms->family && prefix->family != pbrms->family) {
178 vty_out(vty, "Cannot mismatch families within match src/dst\n");
179 return CMD_WARNING_CONFIG_FAILED;
180 }
181
49027ce8
DS
182 pbrms->family = prefix->family;
183
e5c83d9b 184 if (!no) {
5d0e49c4
SW
185 if (pbrms->dst) {
186 if (prefix_same(pbrms->dst, prefix))
187 return CMD_SUCCESS;
f143cffa
SW
188 } else
189 pbrms->dst = prefix_new();
5d0e49c4 190
e5c83d9b 191 prefix_copy(pbrms->dst, prefix);
63265b5c
DS
192 } else
193 prefix_free(&pbrms->dst);
e5c83d9b 194
f143cffa 195 pbr_map_check(pbrms, true);
e5c83d9b
DS
196
197 return CMD_SUCCESS;
198}
199
5e732768
DS
200DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd,
201 "[no] match ip-protocol [tcp|udp]$ip_proto",
202 NO_STR
203 "Match the rest of the command\n"
204 "Choose an ip-protocol\n"
205 "Match on tcp flows\n"
206 "Match on udp flows\n")
207{
208 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
209 struct protoent *p;
210
70219836
DS
211 if (!pbrms)
212 return CMD_WARNING_CONFIG_FAILED;
213
5e732768
DS
214 if (!no) {
215 p = getprotobyname(ip_proto);
216 if (!p) {
217 vty_out(vty, "Unable to convert %s to proto id\n",
218 ip_proto);
219 return CMD_WARNING;
220 }
221
222 pbrms->ip_proto = p->p_proto;
223 } else
224 pbrms->ip_proto = 0;
225
226 return CMD_SUCCESS;
227}
228
a7f0e5c3
DS
229DEFPY(pbr_map_match_src_port, pbr_map_match_src_port_cmd,
230 "[no] match src-port (1-65535)$port",
231 NO_STR
232 "Match the rest of the command\n"
233 "Choose the source port to use\n"
234 "The Source Port\n")
235{
236 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
237
70219836
DS
238 if (!pbrms)
239 return CMD_WARNING_CONFIG_FAILED;
240
a7f0e5c3
DS
241 if (!no) {
242 if (pbrms->src_prt == port)
243 return CMD_SUCCESS;
244 else
245 pbrms->src_prt = port;
246 } else
247 pbrms->src_prt = 0;
248
249 pbr_map_check(pbrms, true);
250
251 return CMD_SUCCESS;
252}
253
254DEFPY(pbr_map_match_dst_port, pbr_map_match_dst_port_cmd,
255 "[no] match dst-port (1-65535)$port",
256 NO_STR
257 "Match the rest of the command\n"
258 "Choose the destination port to use\n"
259 "The Destination Port\n")
260{
261 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
262
70219836
DS
263 if (!pbrms)
264 return CMD_WARNING_CONFIG_FAILED;
265
a7f0e5c3
DS
266 if (!no) {
267 if (pbrms->dst_prt == port)
268 return CMD_SUCCESS;
269 else
270 pbrms->dst_prt = port;
271 } else
272 pbrms->dst_prt = 0;
273
274 pbr_map_check(pbrms, true);
275
276 return CMD_SUCCESS;
277}
278
01f23aff 279DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,
116b86bd 280 "[no] match dscp DSCP$dscp",
01f23aff
WC
281 NO_STR
282 "Match the rest of the command\n"
283 "Match based on IP DSCP field\n"
116b86bd 284 "DSCP value (below 64) or standard codepoint name\n")
01f23aff
WC
285{
286 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
116b86bd
WC
287 char dscpname[100];
288 uint8_t rawDscp;
289
70219836
DS
290 if (!pbrms)
291 return CMD_WARNING_CONFIG_FAILED;
292
116b86bd
WC
293 /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
294 bool isANumber = true;
295 for (int i = 0; i < (int)strlen(dscp); i++) {
296 /* Letters are not numbers */
297 if (!isdigit(dscp[i]))
298 isANumber = false;
299
300 /* Lowercase the dscp enum (if needed) */
301 if (isupper(dscp[i]))
302 dscpname[i] = tolower(dscp[i]);
303 else
304 dscpname[i] = dscp[i];
305 }
306 dscpname[strlen(dscp)] = '\0';
307
308 if (isANumber) {
309 /* dscp passed is a regular number */
310 long dscpAsNum = strtol(dscp, NULL, 0);
311
312 if (dscpAsNum > PBR_DSFIELD_DSCP >> 2) {
313 /* Refuse to install on overflow */
314 vty_out(vty, "dscp (%s) must be less than 64\n", dscp);
315 return CMD_WARNING_CONFIG_FAILED;
316 }
317 rawDscp = dscpAsNum;
318 } else {
319 /* check dscp if it is an enum like cs0 */
320 rawDscp = pbr_map_decode_dscp_enum(dscpname);
321 if (rawDscp > PBR_DSFIELD_DSCP) {
322 vty_out(vty, "Invalid dscp value: %s\n", dscpname);
323 return CMD_WARNING_CONFIG_FAILED;
324 }
325 }
01f23aff
WC
326
327 if (!no) {
116b86bd 328 if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == rawDscp)
01f23aff
WC
329 return CMD_SUCCESS;
330
331 /* Set the DSCP bits of the DSField */
332 pbrms->dsfield =
116b86bd 333 (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2);
01f23aff
WC
334 } else {
335 pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
336 }
337
338 pbr_map_check(pbrms, true);
339
340 return CMD_SUCCESS;
341}
342
343DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd,
344 "[no] match ecn (0-3)$ecn",
345 NO_STR
346 "Match the rest of the command\n"
347 "Match based on IP ECN field\n"
348 "Explicit Congestion Notification\n")
349{
350 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
351
70219836
DS
352 if (!pbrms)
353 return CMD_WARNING_CONFIG_FAILED;
354
01f23aff
WC
355 if (!no) {
356 if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)
357 return CMD_SUCCESS;
358
359 /* Set the ECN bits of the DSField */
360 pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
361 } else {
362 pbrms->dsfield &= ~PBR_DSFIELD_ECN;
363 }
364
365 pbr_map_check(pbrms, true);
366
367 return CMD_SUCCESS;
368}
369
95a9fe02
MM
370DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
371 "[no] match mark (1-4294967295)$mark",
372 NO_STR
373 "Match the rest of the command\n"
374 "Choose the mark value to use\n"
375 "mark\n")
376{
377 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
378
70219836
DS
379 if (!pbrms)
380 return CMD_WARNING_CONFIG_FAILED;
381
95a9fe02 382#ifndef GNU_LINUX
4d4c404b 383 vty_out(vty, "pbr marks are not supported on this platform\n");
95a9fe02
MM
384 return CMD_WARNING_CONFIG_FAILED;
385#endif
386
387 if (!no) {
f143cffa 388 if (pbrms->mark)
5d0e49c4
SW
389 if (pbrms->mark == (uint32_t)mark)
390 return CMD_SUCCESS;
391
5d0e49c4
SW
392 pbrms->mark = (uint32_t)mark;
393 } else
95a9fe02 394 pbrms->mark = 0;
95a9fe02 395
f143cffa 396 pbr_map_check(pbrms, true);
95a9fe02
MM
397
398 return CMD_SUCCESS;
be3b67b5
SW
399}
400
f143cffa
SW
401static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
402{
403 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
404 pbr_map_delete_vrf(pbrms);
405 pbrms->vrf_name[0] = '\0';
406 pbrms->vrf_lookup = false;
407 pbrms->vrf_unchanged = false;
408 }
409}
410
411static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
412{
413 if (pbrms->nhgrp_name)
414 pbr_map_delete_nexthops(pbrms);
415}
416
417static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
418{
419 if (pbrms->nhg)
420 pbr_nht_delete_individual_nexthop(pbrms);
421}
422
423static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
424{
425 pbrms_clear_set_vrf_config(pbrms);
426 pbrms_clear_set_nhg_config(pbrms);
427 pbrms_clear_set_nexthop_config(pbrms);
428
429 pbrms->nhs_installed = false;
430}
95a9fe02 431
d70a31a3
EB
432
433DEFPY(pbr_map_action_queue_id, pbr_map_action_queue_id_cmd,
434 "[no] set queue-id <(1-65535)$queue_id>",
435 NO_STR
436 "Set the rest of the command\n"
437 "Set based on egress port queue id\n"
438 "A valid value in range 1..65535 \n")
439{
440 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
441
70219836
DS
442 if (!pbrms)
443 return CMD_WARNING_CONFIG_FAILED;
444
d70a31a3
EB
445 if (!no)
446 pbrms->action_queue_id = queue_id;
447 else if ((uint32_t)queue_id == pbrms->action_queue_id)
448 pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID;
449
450 pbr_map_check(pbrms, true);
451
452 return CMD_SUCCESS;
453}
454
455DEFPY(pbr_map_action_pcp, pbr_map_action_pcp_cmd, "[no] set pcp <(0-7)$pcp>",
456 NO_STR
457 "Set the rest of the command\n"
458 "Set based on 802.1p Priority Code Point (PCP) value\n"
459 "A valid value in range 0..7\n")
460{
461 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
462
70219836
DS
463 if (!pbrms)
464 return CMD_WARNING_CONFIG_FAILED;
465
d70a31a3
EB
466 if (!no)
467 pbrms->action_pcp = pcp;
468 else if (pcp == pbrms->action_pcp)
469 pbrms->action_pcp = 0;
470
471 pbr_map_check(pbrms, true);
472
473 return CMD_SUCCESS;
474}
475
476DEFPY(pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd,
477 "[no] set vlan <(1-4094)$vlan_id>",
478 NO_STR
479 "Set the rest of the command\n"
480 "Set action for VLAN tagging\n"
481 "A valid value in range 1..4094\n")
482{
483 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
484
70219836
DS
485 if (!pbrms)
486 return CMD_WARNING_CONFIG_FAILED;
487
d70a31a3
EB
488 if (!no)
489 pbrms->action_vlan_id = vlan_id;
490 else if (pbrms->action_vlan_id == vlan_id)
491 pbrms->action_vlan_id = 0;
492
493 pbr_map_check(pbrms, true);
494
495 return CMD_SUCCESS;
496}
497
498DEFPY(pbr_map_action_strip_vlan, pbr_map_action_strip_vlan_cmd,
499 "[no] strip vlan",
500 NO_STR
501 "Strip the vlan tags from frame\n"
502 "Strip any inner vlan tag \n")
503{
504 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
505
70219836
DS
506 if (!pbrms)
507 return CMD_WARNING_CONFIG_FAILED;
508
d70a31a3
EB
509 if (!no)
510 pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY;
511 else
512 pbrms->action_vlan_flags = 0;
513
514 pbr_map_check(pbrms, true);
515
516 return CMD_SUCCESS;
517}
518
519
e5c83d9b 520DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
bce03323 521 "set nexthop-group NHGNAME$name",
be3b67b5
SW
522 "Set for the PBR-MAP\n"
523 "nexthop-group to use\n"
524 "The name of the nexthop-group\n")
e5c83d9b
DS
525{
526 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
527 struct nexthop_group_cmd *nhgc;
e5c83d9b 528
70219836
DS
529 if (!pbrms)
530 return CMD_WARNING_CONFIG_FAILED;
531
e5c83d9b
DS
532 nhgc = nhgc_find(name);
533 if (!nhgc) {
534 vty_out(vty, "Specified nexthop-group %s does not exist\n",
535 name);
be3b67b5
SW
536 vty_out(vty,
537 "PBR-MAP will not be applied until it is created\n");
e5c83d9b
DS
538 }
539
f143cffa
SW
540 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
541 return CMD_SUCCESS;
542
543 /* This is new/replacement config */
544 pbrms_clear_set_config(pbrms);
545
9a7ea213
SW
546 pbr_nht_set_seq_nhg(pbrms, name);
547
f143cffa
SW
548 pbr_map_check(pbrms, true);
549
e5c83d9b
DS
550 return CMD_SUCCESS;
551}
552
bce03323
SW
553DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
554 "no set nexthop-group [NHGNAME$name]",
555 NO_STR
556 "Set for the PBR-MAP\n"
557 "nexthop-group to use\n"
558 "The name of the nexthop-group\n")
559{
560 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
561
70219836
DS
562 if (!pbrms)
563 return CMD_WARNING_CONFIG_FAILED;
564
bce03323
SW
565 pbrms_clear_set_config(pbrms);
566
567 return CMD_SUCCESS;
568}
569
e5c83d9b 570DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
bce03323 571 "set nexthop\
9c0fd853
RW
572 <\
573 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
574 |INTERFACE$intf\
575 >\
e429a2a0 576 [nexthop-vrf NAME$vrf_name]",
e5c83d9b
DS
577 "Set for the PBR-MAP\n"
578 "Specify one of the nexthops in this map\n"
579 "v4 Address\n"
580 "v6 Address\n"
581 "Interface to use\n"
9c0fd853 582 "Interface to use\n"
e5c83d9b
DS
583 "If the nexthop is in a different vrf tell us\n"
584 "The nexthop-vrf Name\n")
585{
586 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
587 struct vrf *vrf;
588 struct nexthop nhop;
f143cffa 589 struct nexthop *nh = NULL;
be3b67b5 590
70219836
DS
591 if (!pbrms)
592 return CMD_WARNING_CONFIG_FAILED;
593
e429a2a0
IR
594 if (vrf_name)
595 vrf = vrf_lookup_by_name(vrf_name);
e5c83d9b
DS
596 else
597 vrf = vrf_lookup_by_id(VRF_DEFAULT);
598
599 if (!vrf) {
0189f722 600 vty_out(vty, "Specified VRF: %s is non-existent\n", vrf_name);
3a9210c2 601 return CMD_WARNING_CONFIG_FAILED;
e5c83d9b
DS
602 }
603
604 memset(&nhop, 0, sizeof(nhop));
605 nhop.vrf_id = vrf->vrf_id;
606
9c0fd853 607 if (intf) {
4ff97453
IR
608 struct interface *ifp = NULL;
609 struct interface *ifptmp;
610 struct vrf *vrftmp;
611 int count = 0;
612
613 if (vrf_is_backend_netns() && vrf_name) {
614 ifp = if_lookup_by_name_vrf(intf, vrf);
615 } else {
616 RB_FOREACH (vrftmp, vrf_name_head, &vrfs_by_name) {
617 ifptmp = if_lookup_by_name_vrf(intf, vrftmp);
618 if (ifptmp) {
619 ifp = ifptmp;
620 count++;
621 if (!vrf_is_backend_netns())
622 break;
623 }
624 }
625 }
0189f722 626
0189f722
DS
627 if (!ifp) {
628 vty_out(vty, "Specified Intf %s does not exist\n",
629 intf);
9c0fd853
RW
630 return CMD_WARNING_CONFIG_FAILED;
631 }
4ff97453
IR
632 if (count > 1) {
633 vty_out(vty,
634 "Specified Intf %s exists in multiple VRFs\n",
635 intf);
636 vty_out(vty, "You must specify the nexthop-vrf\n");
637 return CMD_WARNING_CONFIG_FAILED;
9c0fd853 638 }
096f7609 639 if (ifp->vrf->vrf_id != vrf->vrf_id)
0189f722
DS
640 vty_out(vty,
641 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
096f7609 642 ifp->name, vrf->name, ifp->vrf->name);
0189f722 643 nhop.ifindex = ifp->ifindex;
096f7609 644 nhop.vrf_id = ifp->vrf->vrf_id;
9c0fd853
RW
645 }
646
647 if (addr) {
648 if (addr->sa.sa_family == AF_INET) {
649 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
650 if (intf)
651 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
652 else
653 nhop.type = NEXTHOP_TYPE_IPV4;
cafec8da 654 } else {
9c0fd853
RW
655 nhop.gate.ipv6 = addr->sin6.sin6_addr;
656 if (intf)
657 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
658 else {
659 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
660 vty_out(vty,
661 "Specified a v6 LL with no interface, rejecting\n");
662 return CMD_WARNING_CONFIG_FAILED;
663 }
664 nhop.type = NEXTHOP_TYPE_IPV6;
cafec8da 665 }
cafec8da 666 }
9c0fd853
RW
667 } else
668 nhop.type = NEXTHOP_TYPE_IFINDEX;
e5c83d9b
DS
669
670 if (pbrms->nhg)
671 nh = nexthop_exists(pbrms->nhg, &nhop);
e5c83d9b 672
f143cffa
SW
673 if (nh) /* Same config re-entered */
674 goto done;
e5c83d9b 675
f143cffa
SW
676 /* This is new/replacement config */
677 pbrms_clear_set_config(pbrms);
e5c83d9b 678
f143cffa 679 pbr_nht_add_individual_nexthop(pbrms, &nhop);
e5c83d9b 680
f143cffa 681 pbr_map_check(pbrms, true);
e5c83d9b 682
f143cffa 683done:
cb254f41
SW
684 if (nhop.type == NEXTHOP_TYPE_IFINDEX
685 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
686 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
9c0fd853
RW
687 struct interface *ifp;
688
689 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
690 if (ifp)
691 pbr_nht_nexthop_interface_update(ifp);
692 }
693
e5c83d9b
DS
694 return CMD_SUCCESS;
695}
696
bce03323
SW
697DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
698 "no set nexthop\
699 [<\
700 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
701 |INTERFACE$intf\
702 >\
703 [nexthop-vrf NAME$vrf_name]]",
be3b67b5
SW
704 NO_STR
705 "Set for the PBR-MAP\n"
bce03323
SW
706 "Specify one of the nexthops in this map\n"
707 "v4 Address\n"
708 "v6 Address\n"
709 "Interface to use\n"
710 "Interface to use\n"
711 "If the nexthop is in a different vrf tell us\n"
712 "The nexthop-vrf Name\n")
713{
714 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
715
70219836
DS
716 if (!pbrms)
717 return CMD_WARNING_CONFIG_FAILED;
718
bce03323
SW
719 pbrms_clear_set_config(pbrms);
720
721 return CMD_SUCCESS;
722}
723
724DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
725 "set vrf <NAME$vrf_name|unchanged>",
726 "Set for the PBR-MAP\n"
be3b67b5
SW
727 "Specify the VRF for this map\n"
728 "The VRF Name\n"
729 "Use the interface's VRF for lookup\n")
730{
731 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
be3b67b5 732
70219836
DS
733 if (!pbrms)
734 return CMD_WARNING_CONFIG_FAILED;
735
9bf1b0f7 736 /*
f143cffa 737 * If an equivalent set vrf * exists, just return success.
9bf1b0f7 738 */
f143cffa
SW
739 if (vrf_name && pbrms->vrf_lookup
740 && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0)
f3f2c78a 741 return CMD_SUCCESS;
f143cffa 742 else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */
f3f2c78a 743 return CMD_SUCCESS;
9bf1b0f7 744
bce03323
SW
745 if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) {
746 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
747 return CMD_WARNING_CONFIG_FAILED;
748 }
749
f143cffa
SW
750 /* This is new/replacement config */
751 pbrms_clear_set_config(pbrms);
be3b67b5
SW
752
753 if (vrf_name) {
be3b67b5
SW
754 pbrms->vrf_lookup = true;
755 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
756 } else
757 pbrms->vrf_unchanged = true;
758
f143cffa 759 pbr_map_check(pbrms, true);
be3b67b5 760
f3f2c78a 761 return CMD_SUCCESS;
be3b67b5
SW
762}
763
bce03323
SW
764DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
765 "no set vrf [<NAME$vrf_name|unchanged>]",
766 NO_STR
767 "Set for the PBR-MAP\n"
768 "Specify the VRF for this map\n"
769 "The VRF Name\n"
770 "Use the interface's VRF for lookup\n")
771{
772 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
773
70219836
DS
774 if (!pbrms)
775 return CMD_WARNING_CONFIG_FAILED;
776
bce03323
SW
777 pbrms_clear_set_config(pbrms);
778
779 return CMD_SUCCESS;
780}
781
e5c83d9b
DS
782DEFPY (pbr_policy,
783 pbr_policy_cmd,
17f8c652 784 "[no] pbr-policy PBRMAP$mapname",
e5c83d9b
DS
785 NO_STR
786 "Policy to use\n"
787 "Name of the pbr-map to apply\n")
788{
789 VTY_DECLVAR_CONTEXT(interface, ifp);
790 struct pbr_map *pbrm, *old_pbrm;
791 struct pbr_interface *pbr_ifp = ifp->info;
792
6eb499b0 793 old_pbrm = NULL;
e5c83d9b
DS
794 pbrm = pbrm_find(mapname);
795
b13e5ad6 796 if (!pbr_ifp) {
d6416967
QY
797 /* we don't want one and we don't have one, so... */
798 if (no)
799 return CMD_SUCCESS;
800
801 /* Some one could have fat fingered the interface name */
b13e5ad6
DS
802 pbr_ifp = pbr_if_new(ifp);
803 }
804
e5c83d9b
DS
805 if (no) {
806 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
5f504f14 807 pbr_ifp->mapname[0] = '\0';
e5c83d9b
DS
808 if (pbrm)
809 pbr_map_interface_delete(pbrm, ifp);
810 }
811 } else {
5f504f14
QY
812 if (strcmp(pbr_ifp->mapname, "") != 0) {
813 old_pbrm = pbrm_find(pbr_ifp->mapname);
6eb499b0
DS
814
815 /*
816 * So if we have an old pbrm we should only
817 * delete it if we are actually deleting and
818 * moving to a new pbrm
819 */
820 if (old_pbrm && old_pbrm != pbrm)
5f504f14 821 pbr_map_interface_delete(old_pbrm, ifp);
e5c83d9b 822 }
5f504f14
QY
823 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
824 "%s", mapname);
6eb499b0
DS
825
826 /*
827 * So only reinstall if the old_pbrm and this pbrm are
828 * different.
829 */
830 if (pbrm && pbrm != old_pbrm)
5f504f14 831 pbr_map_add_interface(pbrm, ifp);
e5c83d9b
DS
832 }
833
834 return CMD_SUCCESS;
835}
836
837DEFPY (show_pbr,
838 show_pbr_cmd,
ef18ed6e 839 "show pbr",
e5c83d9b 840 SHOW_STR
24a21176 841 PBR_STR)
e5c83d9b
DS
842{
843 pbr_nht_write_table_range(vty);
844 pbr_nht_write_rule_range(vty);
845
846 return CMD_SUCCESS;
847}
848
fcf29c69
DS
849static void
850pbrms_nexthop_group_write_individual_nexthop(
851 struct vty *vty, const struct pbr_map_sequence *pbrms)
852{
853 struct pbr_nexthop_group_cache find;
854 struct pbr_nexthop_group_cache *pnhgc;
855 struct pbr_nexthop_cache lookup;
856 struct pbr_nexthop_cache *pnhc;
857
fcf29c69
DS
858 memset(&find, 0, sizeof(find));
859 strlcpy(find.name, pbrms->internal_nhg_name, sizeof(find.name));
860
861 pnhgc = hash_lookup(pbr_nhg_hash, &find);
862 assert(pnhgc);
863
734bf907 864 lookup.nexthop = *pbrms->nhg->nexthop;
fcf29c69 865 pnhc = hash_lookup(pnhgc->nhh, &lookup);
7cbdabff
DS
866
867 nexthop_group_write_nexthop_simple(
868 vty, pbrms->nhg->nexthop,
734bf907
DS
869 pnhc->nexthop.ifindex != 0 ? pnhc->intf_name : NULL);
870 if (pnhc->nexthop.vrf_id != VRF_DEFAULT)
fcf29c69
DS
871 vty_out(vty, " nexthop-vrf %s", pnhc->vrf_name);
872
873 vty_out(vty, "\n");
874}
875
1eaa8361
SW
876static void vty_show_pbrms(struct vty *vty,
877 const struct pbr_map_sequence *pbrms, bool detail)
878{
1eaa8361
SW
879 char rbuf[64];
880
881 if (pbrms->reason)
882 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
3259cde6
SW
883
884 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
885
886 if (detail)
b740126d 887 vty_out(vty, " Installed: %" PRIu64 "(%u) Reason: %s\n",
3259cde6
SW
888 pbrms->installed, pbrms->unique,
889 pbrms->reason ? rbuf : "Valid");
890 else
b740126d 891 vty_out(vty, " Installed: %s Reason: %s\n",
3259cde6
SW
892 pbrms->installed ? "yes" : "no",
893 pbrms->reason ? rbuf : "Valid");
1eaa8361 894
5e732768
DS
895 if (pbrms->ip_proto) {
896 struct protoent *p;
897
898 p = getprotobynumber(pbrms->ip_proto);
899 vty_out(vty, " IP Protocol Match: %s\n", p->p_name);
900 }
901
1eaa8361 902 if (pbrms->src)
59f47eb0 903 vty_out(vty, " SRC IP Match: %pFX\n", pbrms->src);
1eaa8361 904 if (pbrms->dst)
59f47eb0
AK
905 vty_out(vty, " DST IP Match: %pFX\n", pbrms->dst);
906 if (pbrms->src_prt)
907 vty_out(vty, " SRC Port Match: %u\n", pbrms->src_prt);
908 if (pbrms->dst_prt)
909 vty_out(vty, " DST Port Match: %u\n", pbrms->dst_prt);
01f23aff
WC
910 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
911 vty_out(vty, " DSCP Match: %u\n",
912 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
913 if (pbrms->dsfield & PBR_DSFIELD_ECN)
914 vty_out(vty, " ECN Match: %u\n",
915 pbrms->dsfield & PBR_DSFIELD_ECN);
1eaa8361 916 if (pbrms->mark)
b740126d 917 vty_out(vty, " MARK Match: %u\n", pbrms->mark);
1eaa8361 918
d70a31a3
EB
919 if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
920 vty_out(vty, " Set Queue ID %u\n",
921 pbrms->action_queue_id);
922
923 if (pbrms->action_vlan_id != 0)
924 vty_out(vty, " Set VLAN ID %u\n", pbrms->action_vlan_id);
925 if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
926 vty_out(vty, " Strip VLAN ID\n");
927 if (pbrms->action_pcp)
928 vty_out(vty, " Set PCP %u\n", pbrms->action_pcp);
929
930
1eaa8361 931 if (pbrms->nhgrp_name) {
b740126d 932 vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
add5e0a4 933
3259cde6 934 if (detail)
b740126d
SW
935 vty_out(vty,
936 " Installed: %u(%d) Tableid: %d\n",
3259cde6 937 pbrms->nhs_installed,
add5e0a4
SW
938 pbr_nht_get_installed(pbrms->nhgrp_name),
939 pbr_nht_get_table(pbrms->nhgrp_name));
3259cde6 940 else
b740126d 941 vty_out(vty, " Installed: %s Tableid: %d\n",
add5e0a4
SW
942 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
943 : "no",
944 pbr_nht_get_table(pbrms->nhgrp_name));
945
1eaa8361 946 } else if (pbrms->nhg) {
b740126d 947 vty_out(vty, " ");
fcf29c69 948 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
3259cde6 949 if (detail)
b740126d
SW
950 vty_out(vty,
951 " Installed: %u(%d) Tableid: %d\n",
3259cde6
SW
952 pbrms->nhs_installed,
953 pbr_nht_get_installed(pbrms->internal_nhg_name),
954 pbr_nht_get_table(pbrms->internal_nhg_name));
955 else
b740126d 956 vty_out(vty, " Installed: %s Tableid: %d\n",
3259cde6
SW
957 pbr_nht_get_installed(pbrms->internal_nhg_name)
958 ? "yes"
959 : "no",
960 pbr_nht_get_table(pbrms->internal_nhg_name));
961
1eaa8361 962 } else if (pbrms->vrf_unchanged) {
b740126d 963 vty_out(vty, " VRF Unchanged (use interface vrf)\n");
1eaa8361 964 } else if (pbrms->vrf_lookup) {
b740126d 965 vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name);
1eaa8361 966 } else {
b740126d 967 vty_out(vty, " Nexthop-Group: Unknown Installed: no\n");
1eaa8361
SW
968 }
969}
970
1a8cafe1
WC
971static void vty_json_pbrms(json_object *j, struct vty *vty,
972 const struct pbr_map_sequence *pbrms)
973{
81c0078e 974 json_object *jpbrm, *nexthop_group;
1a8cafe1
WC
975 char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
976 : pbrms->internal_nhg_name;
1a8cafe1
WC
977 char rbuf[64];
978
979 jpbrm = json_object_new_object();
980
81c0078e
WC
981 json_object_int_add(jpbrm, "id", pbrms->unique);
982
1a8cafe1
WC
983 if (pbrms->reason)
984 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
985
986 json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
987 json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
1a8cafe1 988 json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
3e81618d 989 json_object_boolean_add(jpbrm, "installed",
1a8cafe1 990 pbr_nht_get_installed(nhg_name));
81c0078e
WC
991 json_object_string_add(jpbrm, "installedReason",
992 pbrms->reason ? rbuf : "Valid");
1a8cafe1 993
81c0078e 994 if (nhg_name) {
1a8cafe1
WC
995 nexthop_group = json_object_new_object();
996
3e81618d 997 json_object_int_add(nexthop_group, "tableId",
1a8cafe1 998 pbr_nht_get_table(nhg_name));
81c0078e 999 json_object_string_add(nexthop_group, "name", nhg_name);
3e81618d 1000 json_object_boolean_add(nexthop_group, "installed",
1a8cafe1 1001 pbr_nht_get_installed(nhg_name));
3e81618d 1002 json_object_int_add(nexthop_group, "installedInternally",
81c0078e 1003 pbrms->nhs_installed);
1a8cafe1
WC
1004
1005 json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
1a8cafe1
WC
1006 }
1007
81c0078e
WC
1008 if (pbrms->vrf_lookup)
1009 json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
1a8cafe1 1010
81c0078e 1011 if (pbrms->src)
60200fdd 1012 json_object_string_addf(jpbrm, "matchSrc", "%pFX", pbrms->src);
81c0078e 1013 if (pbrms->dst)
60200fdd 1014 json_object_string_addf(jpbrm, "matchDst", "%pFX", pbrms->dst);
81c0078e
WC
1015 if (pbrms->mark)
1016 json_object_int_add(jpbrm, "matchMark", pbrms->mark);
d301f153
WC
1017 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
1018 json_object_int_add(jpbrm, "matchDscp",
1019 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
1020 if (pbrms->dsfield & PBR_DSFIELD_ECN)
1021 json_object_int_add(jpbrm, "matchEcn",
1022 pbrms->dsfield & PBR_DSFIELD_ECN);
1a8cafe1
WC
1023
1024 json_object_array_add(j, jpbrm);
1025}
1026
1eaa8361
SW
1027static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
1028 bool detail)
1029{
1030 struct pbr_map_sequence *pbrms;
1031 struct listnode *node;
1032
1ce24b9b
SW
1033 vty_out(vty, " pbr-map %s valid: %s\n", pbrm->name,
1034 pbrm->valid ? "yes" : "no");
1eaa8361
SW
1035
1036 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
1037 vty_show_pbrms(vty, pbrms, detail);
1038}
1039
1a8cafe1
WC
1040static void vty_json_pbr_map(json_object *j, struct vty *vty,
1041 const struct pbr_map *pbrm)
1042{
1043 struct pbr_map_sequence *pbrms;
1044 struct listnode *node;
1045 json_object *jpbrms;
1046
1047 json_object_string_add(j, "name", pbrm->name);
3e81618d 1048 json_object_boolean_add(j, "valid", pbrm->valid);
1a8cafe1
WC
1049
1050 jpbrms = json_object_new_array();
1051
1052 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
1053 vty_json_pbrms(jpbrms, vty, pbrms);
1054
f9368f89 1055 json_object_object_add(j, "policies", jpbrms);
1a8cafe1
WC
1056}
1057
e5c83d9b
DS
1058DEFPY (show_pbr_map,
1059 show_pbr_map_cmd,
1a8cafe1 1060 "show pbr map [NAME$name] [detail$detail|json$json]",
e5c83d9b 1061 SHOW_STR
24a21176 1062 PBR_STR
e5c83d9b
DS
1063 "PBR Map\n"
1064 "PBR Map Name\n"
1a8cafe1
WC
1065 "Detailed information\n"
1066 JSON_STR)
e5c83d9b 1067{
e5c83d9b 1068 struct pbr_map *pbrm;
1a8cafe1
WC
1069 json_object *j = NULL;
1070
1071 if (json)
dadba1a2 1072 j = json_object_new_array();
e5c83d9b
DS
1073
1074 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
1a8cafe1 1075 json_object *this_map = NULL;
e5c83d9b
DS
1076 if (name && strcmp(name, pbrm->name) != 0)
1077 continue;
1078
1a8cafe1
WC
1079 if (j)
1080 this_map = json_object_new_object();
1081
1082 if (this_map) {
1083 vty_json_pbr_map(this_map, vty, pbrm);
1084
dadba1a2 1085 json_object_array_add(j, this_map);
1a8cafe1
WC
1086 continue;
1087 }
1088
1eaa8361 1089 vty_show_pbr_map(vty, pbrm, detail);
e5c83d9b 1090 }
1a8cafe1 1091
c48349e3 1092 if (j)
760441ea 1093 vty_json(vty, j);
1a8cafe1 1094
e5c83d9b
DS
1095 return CMD_SUCCESS;
1096}
1097
1098DEFPY(show_pbr_nexthop_group,
1099 show_pbr_nexthop_group_cmd,
010dd8ed 1100 "show pbr nexthop-groups [WORD$word] [json$json]",
e5c83d9b 1101 SHOW_STR
24a21176 1102 PBR_STR
e5c83d9b 1103 "Nexthop Groups\n"
010dd8ed
WC
1104 "Optional Name of the nexthop group\n"
1105 JSON_STR)
e5c83d9b 1106{
010dd8ed
WC
1107 json_object *j = NULL;
1108
1109 if (json)
dadba1a2 1110 j = json_object_new_array();
010dd8ed
WC
1111
1112 if (j) {
1113 pbr_nht_json_nexthop_group(j, word);
1114
760441ea 1115 vty_json(vty, j);
010dd8ed
WC
1116 } else
1117 pbr_nht_show_nexthop_group(vty, word);
1118
e5c83d9b
DS
1119
1120 return CMD_SUCCESS;
1121}
1122
1123DEFPY (show_pbr_interface,
1124 show_pbr_interface_cmd,
7a7b0c13 1125 "show pbr interface [NAME$name] [json$json]",
e5c83d9b 1126 SHOW_STR
24a21176 1127 PBR_STR
e5c83d9b 1128 "PBR Interface\n"
7a7b0c13
WC
1129 "PBR Interface Name\n"
1130 JSON_STR)
e5c83d9b 1131{
d3765386 1132 struct interface *ifp;
e5c83d9b
DS
1133 struct vrf *vrf;
1134 struct pbr_interface *pbr_ifp;
7a7b0c13
WC
1135 json_object *j = NULL;
1136
1137 if (json)
dadba1a2 1138 j = json_object_new_array();
e5c83d9b
DS
1139
1140 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
1141 FOR_ALL_INTERFACES(vrf, ifp) {
1142 struct pbr_map *pbrm;
7a7b0c13
WC
1143 json_object *this_iface = NULL;
1144
1145 if (j)
1146 this_iface = json_object_new_object();
e5c83d9b 1147
c195ae78
DS
1148 if (!ifp->info) {
1149 json_object_free(this_iface);
1c33fb1d 1150 continue;
c195ae78 1151 }
1c33fb1d 1152
c195ae78
DS
1153 if (name && strcmp(ifp->name, name) != 0) {
1154 json_object_free(this_iface);
e5c83d9b 1155 continue;
c195ae78 1156 }
e5c83d9b
DS
1157
1158 pbr_ifp = ifp->info;
1159
c195ae78
DS
1160 if (strcmp(pbr_ifp->mapname, "") == 0) {
1161 json_object_free(this_iface);
e5c83d9b 1162 continue;
c195ae78 1163 }
e5c83d9b
DS
1164
1165 pbrm = pbrm_find(pbr_ifp->mapname);
7a7b0c13
WC
1166
1167 if (this_iface) {
1168 json_object_string_add(this_iface, "name",
1169 ifp->name);
1170 json_object_int_add(this_iface, "index",
1171 ifp->ifindex);
1172 json_object_string_add(this_iface, "policy",
1173 pbr_ifp->mapname);
3e81618d 1174 json_object_boolean_add(this_iface, "valid",
7a7b0c13
WC
1175 pbrm);
1176
dadba1a2 1177 json_object_array_add(j, this_iface);
7a7b0c13
WC
1178 continue;
1179 }
1180
e5c83d9b
DS
1181 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
1182 ifp->ifindex, pbr_ifp->mapname);
1183 if (!pbrm)
1184 vty_out(vty, " (map doesn't exist)");
1185 vty_out(vty, "\n");
1186 }
1187 }
1188
c48349e3 1189 if (j)
760441ea 1190 vty_json(vty, j);
7a7b0c13 1191
e5c83d9b
DS
1192 return CMD_SUCCESS;
1193}
1194
e14f43cc 1195/* PBR debugging CLI ------------------------------------------------------- */
e14f43cc 1196
62b346ee 1197static struct cmd_node debug_node = {
f4b8291f 1198 .name = "debug",
62b346ee
DL
1199 .node = DEBUG_NODE,
1200 .prompt = "",
612c2c15 1201 .config_write = pbr_debug_config_write,
62b346ee 1202};
e14f43cc
QY
1203
1204DEFPY(debug_pbr,
1205 debug_pbr_cmd,
1206 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
1207 NO_STR
1208 DEBUG_STR
24a21176 1209 PBR_STR
e14f43cc
QY
1210 "Policy maps\n"
1211 "PBRD <-> Zebra communications\n"
1212 "Nexthop tracking\n"
1213 "Events\n")
1214{
1215 uint32_t mode = DEBUG_NODE2MODE(vty->node);
1216
1217 if (map)
1218 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
1219 if (zebra)
1220 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
1221 if (nht)
1222 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
1223 if (events)
1224 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
1225
1226 /* no specific debug --> act on all of them */
1227 if (strmatch(argv[argc - 1]->text, "pbr"))
1228 pbr_debug_set_all(mode, !no);
1229
1230 return CMD_SUCCESS;
1231}
1232
1233DEFUN_NOSH(show_debugging_pbr,
1234 show_debugging_pbr_cmd,
1235 "show debugging [pbr]",
1236 SHOW_STR
1237 DEBUG_STR
24a21176 1238 PBR_STR)
e14f43cc
QY
1239{
1240 vty_out(vty, "PBR debugging status:\n");
1241
1242 pbr_debug_config_write_helper(vty, false);
1243
cf00164b
DS
1244 cmd_show_lib_debugs(vty);
1245
e14f43cc
QY
1246 return CMD_SUCCESS;
1247}
1248
e14f43cc
QY
1249/* ------------------------------------------------------------------------- */
1250
1251
e5c83d9b
DS
1252static int pbr_interface_config_write(struct vty *vty)
1253{
1254 struct interface *ifp;
1255 struct vrf *vrf;
1256
1257 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1258 FOR_ALL_INTERFACES (vrf, ifp) {
788a036f 1259 if_vty_config_start(vty, ifp);
e5c83d9b 1260
91e5b43a
RW
1261 if (ifp->desc)
1262 vty_out(vty, " description %s\n", ifp->desc);
1263
e5c83d9b
DS
1264 pbr_map_write_interfaces(vty, ifp);
1265
788a036f 1266 if_vty_config_end(vty);
e5c83d9b
DS
1267 }
1268 }
1269
1270 return 1;
1271}
1272
612c2c15 1273static int pbr_vty_map_config_write(struct vty *vty);
e5c83d9b 1274/* PBR map node structure. */
62b346ee 1275static struct cmd_node pbr_map_node = {
f4b8291f 1276 .name = "pbr-map",
62b346ee 1277 .node = PBRMAP_NODE,
24389580 1278 .parent_node = CONFIG_NODE,
62b346ee 1279 .prompt = "%s(config-pbr-map)# ",
612c2c15 1280 .config_write = pbr_vty_map_config_write,
62b346ee 1281};
e5c83d9b
DS
1282
1283static int pbr_vty_map_config_write_sequence(struct vty *vty,
1284 struct pbr_map *pbrm,
1285 struct pbr_map_sequence *pbrms)
1286{
5e44f18f 1287 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
e5c83d9b
DS
1288
1289 if (pbrms->src)
2dbe669b 1290 vty_out(vty, " match src-ip %pFX\n", pbrms->src);
e5c83d9b
DS
1291
1292 if (pbrms->dst)
2dbe669b 1293 vty_out(vty, " match dst-ip %pFX\n", pbrms->dst);
e5c83d9b 1294
a7f0e5c3
DS
1295 if (pbrms->src_prt)
1296 vty_out(vty, " match src-port %u\n", pbrms->src_prt);
1297 if (pbrms->dst_prt)
1298 vty_out(vty, " match dst-port %u\n", pbrms->dst_prt);
1299
5e732768
DS
1300 if (pbrms->ip_proto) {
1301 struct protoent *p;
1302
1303 p = getprotobynumber(pbrms->ip_proto);
1304 vty_out(vty, " match ip-protocol %s\n", p->p_name);
1305 }
1306
01f23aff
WC
1307 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
1308 vty_out(vty, " match dscp %u\n",
1309 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
1310
1311 if (pbrms->dsfield & PBR_DSFIELD_ECN)
1312 vty_out(vty, " match ecn %u\n",
1313 pbrms->dsfield & PBR_DSFIELD_ECN);
1314
95a9fe02
MM
1315 if (pbrms->mark)
1316 vty_out(vty, " match mark %u\n", pbrms->mark);
1317
d70a31a3
EB
1318
1319 if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
1320 vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id);
1321
1322 if (pbrms->action_pcp)
1323 vty_out(vty, " set pcp %d\n", pbrms->action_pcp);
1324
1325 if (pbrms->action_vlan_id)
1326 vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id);
1327
1328 if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY)
1329 vty_out(vty, " strip vlan any\n");
1330
be3b67b5
SW
1331 if (pbrms->vrf_unchanged)
1332 vty_out(vty, " set vrf unchanged\n");
1333
1334 if (pbrms->vrf_lookup)
1335 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
1336
e5c83d9b 1337 if (pbrms->nhgrp_name)
7dce96f0 1338 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
e5c83d9b
DS
1339
1340 if (pbrms->nhg) {
7dce96f0 1341 vty_out(vty, " set ");
fcf29c69 1342 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
e5c83d9b
DS
1343 }
1344
07679ad9 1345 vty_out(vty, "exit\n");
5e44f18f 1346 vty_out(vty, "!\n");
e5c83d9b
DS
1347 return 1;
1348}
1349
1350static int pbr_vty_map_config_write(struct vty *vty)
1351{
1352 struct pbr_map *pbrm;
1353
1354 pbr_nht_write_table_range(vty);
1355 pbr_nht_write_rule_range(vty);
1356
1357 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
1358 struct pbr_map_sequence *pbrms;
1359 struct listnode *node;
1360
d3765386 1361 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
e5c83d9b 1362 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
e5c83d9b
DS
1363 }
1364
1365 return 1;
1366}
1367
17f8c652
DS
1368static void pbr_map_completer(vector comps, struct cmd_token *token)
1369{
1370 struct pbr_map *pbrm;
1371
1372 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
1373 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
1374}
1375
1376static const struct cmd_variable_handler pbr_map_name[] = {
1377 {
1378 .tokenname = "PBRMAP", .completions = pbr_map_completer,
1379 },
1380 {
1381 .completions = NULL
1382 }
1383};
1384
f5eef2d5
IR
1385extern struct zebra_privs_t pbr_privs;
1386
e5c83d9b
DS
1387void pbr_vty_init(void)
1388{
17f8c652
DS
1389 cmd_variable_handler_register(pbr_map_name);
1390
cfc369c4 1391 vrf_cmd_init(NULL);
f5eef2d5 1392
9da01b0b 1393 if_cmd_init(pbr_interface_config_write);
e5c83d9b 1394
612c2c15 1395 install_node(&pbr_map_node);
e5c83d9b 1396
e14f43cc 1397 /* debug */
612c2c15 1398 install_node(&debug_node);
eed041e8 1399 install_element(ENABLE_NODE, &debug_pbr_cmd);
e14f43cc 1400 install_element(CONFIG_NODE, &debug_pbr_cmd);
dd73744d 1401 install_element(ENABLE_NODE, &show_debugging_pbr_cmd);
e14f43cc 1402
e5c83d9b
DS
1403 install_default(PBRMAP_NODE);
1404
1405 install_element(CONFIG_NODE, &pbr_map_cmd);
1406 install_element(CONFIG_NODE, &no_pbr_map_cmd);
7bec514c 1407 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
b246eb8a 1408 install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);
e5c83d9b 1409 install_element(INTERFACE_NODE, &pbr_policy_cmd);
5e732768 1410 install_element(PBRMAP_NODE, &pbr_map_match_ip_proto_cmd);
a7f0e5c3
DS
1411 install_element(PBRMAP_NODE, &pbr_map_match_src_port_cmd);
1412 install_element(PBRMAP_NODE, &pbr_map_match_dst_port_cmd);
e5c83d9b
DS
1413 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
1414 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
01f23aff
WC
1415 install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
1416 install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
95a9fe02 1417 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
d70a31a3
EB
1418 install_element(PBRMAP_NODE, &pbr_map_action_queue_id_cmd);
1419 install_element(PBRMAP_NODE, &pbr_map_action_strip_vlan_cmd);
1420 install_element(PBRMAP_NODE, &pbr_map_action_vlan_id_cmd);
1421 install_element(PBRMAP_NODE, &pbr_map_action_pcp_cmd);
e5c83d9b 1422 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
bce03323 1423 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
e5c83d9b 1424 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
bce03323 1425 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_cmd);
be3b67b5 1426 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
bce03323 1427 install_element(PBRMAP_NODE, &no_pbr_map_vrf_cmd);
e5c83d9b
DS
1428 install_element(VIEW_NODE, &show_pbr_cmd);
1429 install_element(VIEW_NODE, &show_pbr_map_cmd);
1430 install_element(VIEW_NODE, &show_pbr_interface_cmd);
1431 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
e5c83d9b 1432}