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