]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_vty.c
Merge pull request #8488 from mjstapp/more_workqueue
[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
67765a23
SW
140 if (pbrms->dst && pbrms->family && prefix->family != pbrms->family) {
141 vty_out(vty, "Cannot mismatch families within match src/dst\n");
142 return CMD_WARNING_CONFIG_FAILED;
143 }
144
49027ce8
DS
145 pbrms->family = prefix->family;
146
e5c83d9b 147 if (!no) {
5d0e49c4
SW
148 if (pbrms->src) {
149 if (prefix_same(pbrms->src, prefix))
150 return CMD_SUCCESS;
f143cffa
SW
151 } else
152 pbrms->src = prefix_new();
5d0e49c4 153
e5c83d9b 154 prefix_copy(pbrms->src, prefix);
63265b5c
DS
155 } else
156 prefix_free(&pbrms->src);
e5c83d9b 157
f143cffa 158 pbr_map_check(pbrms, true);
e5c83d9b
DS
159
160 return CMD_SUCCESS;
161}
162
163DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
164 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
165 NO_STR
166 "Match the rest of the command\n"
6c4c9a6c 167 "Choose the dst ip or ipv6 prefix to use\n"
e5c83d9b
DS
168 "v4 Prefix\n"
169 "v6 Prefix\n")
170{
171 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b 172
67765a23
SW
173 if (pbrms->src && pbrms->family && prefix->family != pbrms->family) {
174 vty_out(vty, "Cannot mismatch families within match src/dst\n");
175 return CMD_WARNING_CONFIG_FAILED;
176 }
177
49027ce8
DS
178 pbrms->family = prefix->family;
179
e5c83d9b 180 if (!no) {
5d0e49c4
SW
181 if (pbrms->dst) {
182 if (prefix_same(pbrms->dst, prefix))
183 return CMD_SUCCESS;
f143cffa
SW
184 } else
185 pbrms->dst = prefix_new();
5d0e49c4 186
e5c83d9b 187 prefix_copy(pbrms->dst, prefix);
63265b5c
DS
188 } else
189 prefix_free(&pbrms->dst);
e5c83d9b 190
f143cffa 191 pbr_map_check(pbrms, true);
e5c83d9b
DS
192
193 return CMD_SUCCESS;
194}
195
01f23aff 196DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,
116b86bd 197 "[no] match dscp DSCP$dscp",
01f23aff
WC
198 NO_STR
199 "Match the rest of the command\n"
200 "Match based on IP DSCP field\n"
116b86bd 201 "DSCP value (below 64) or standard codepoint name\n")
01f23aff
WC
202{
203 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
116b86bd
WC
204 char dscpname[100];
205 uint8_t rawDscp;
206
207 /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
208 bool isANumber = true;
209 for (int i = 0; i < (int)strlen(dscp); i++) {
210 /* Letters are not numbers */
211 if (!isdigit(dscp[i]))
212 isANumber = false;
213
214 /* Lowercase the dscp enum (if needed) */
215 if (isupper(dscp[i]))
216 dscpname[i] = tolower(dscp[i]);
217 else
218 dscpname[i] = dscp[i];
219 }
220 dscpname[strlen(dscp)] = '\0';
221
222 if (isANumber) {
223 /* dscp passed is a regular number */
224 long dscpAsNum = strtol(dscp, NULL, 0);
225
226 if (dscpAsNum > PBR_DSFIELD_DSCP >> 2) {
227 /* Refuse to install on overflow */
228 vty_out(vty, "dscp (%s) must be less than 64\n", dscp);
229 return CMD_WARNING_CONFIG_FAILED;
230 }
231 rawDscp = dscpAsNum;
232 } else {
233 /* check dscp if it is an enum like cs0 */
234 rawDscp = pbr_map_decode_dscp_enum(dscpname);
235 if (rawDscp > PBR_DSFIELD_DSCP) {
236 vty_out(vty, "Invalid dscp value: %s\n", dscpname);
237 return CMD_WARNING_CONFIG_FAILED;
238 }
239 }
01f23aff
WC
240
241 if (!no) {
116b86bd 242 if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == rawDscp)
01f23aff
WC
243 return CMD_SUCCESS;
244
245 /* Set the DSCP bits of the DSField */
246 pbrms->dsfield =
116b86bd 247 (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2);
01f23aff
WC
248 } else {
249 pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
250 }
251
252 pbr_map_check(pbrms, true);
253
254 return CMD_SUCCESS;
255}
256
257DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd,
258 "[no] match ecn (0-3)$ecn",
259 NO_STR
260 "Match the rest of the command\n"
261 "Match based on IP ECN field\n"
262 "Explicit Congestion Notification\n")
263{
264 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
265
266 if (!no) {
267 if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)
268 return CMD_SUCCESS;
269
270 /* Set the ECN bits of the DSField */
271 pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
272 } else {
273 pbrms->dsfield &= ~PBR_DSFIELD_ECN;
274 }
275
276 pbr_map_check(pbrms, true);
277
278 return CMD_SUCCESS;
279}
280
95a9fe02
MM
281DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
282 "[no] match mark (1-4294967295)$mark",
283 NO_STR
284 "Match the rest of the command\n"
285 "Choose the mark value to use\n"
286 "mark\n")
287{
288 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
289
290#ifndef GNU_LINUX
291 vty_out(vty, "pbr marks are not supported on this platform");
292 return CMD_WARNING_CONFIG_FAILED;
293#endif
294
295 if (!no) {
f143cffa 296 if (pbrms->mark)
5d0e49c4
SW
297 if (pbrms->mark == (uint32_t)mark)
298 return CMD_SUCCESS;
299
5d0e49c4
SW
300 pbrms->mark = (uint32_t)mark;
301 } else
95a9fe02 302 pbrms->mark = 0;
95a9fe02 303
f143cffa 304 pbr_map_check(pbrms, true);
95a9fe02
MM
305
306 return CMD_SUCCESS;
be3b67b5
SW
307}
308
f143cffa
SW
309static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
310{
311 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
312 pbr_map_delete_vrf(pbrms);
313 pbrms->vrf_name[0] = '\0';
314 pbrms->vrf_lookup = false;
315 pbrms->vrf_unchanged = false;
316 }
317}
318
319static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
320{
321 if (pbrms->nhgrp_name)
322 pbr_map_delete_nexthops(pbrms);
323}
324
325static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
326{
327 if (pbrms->nhg)
328 pbr_nht_delete_individual_nexthop(pbrms);
329}
330
331static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
332{
333 pbrms_clear_set_vrf_config(pbrms);
334 pbrms_clear_set_nhg_config(pbrms);
335 pbrms_clear_set_nexthop_config(pbrms);
336
337 pbrms->nhs_installed = false;
338}
95a9fe02 339
e5c83d9b 340DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
bce03323 341 "set nexthop-group NHGNAME$name",
be3b67b5
SW
342 "Set for the PBR-MAP\n"
343 "nexthop-group to use\n"
344 "The name of the nexthop-group\n")
e5c83d9b
DS
345{
346 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
347 struct nexthop_group_cmd *nhgc;
e5c83d9b
DS
348
349 nhgc = nhgc_find(name);
350 if (!nhgc) {
351 vty_out(vty, "Specified nexthop-group %s does not exist\n",
352 name);
be3b67b5
SW
353 vty_out(vty,
354 "PBR-MAP will not be applied until it is created\n");
e5c83d9b
DS
355 }
356
f143cffa
SW
357 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
358 return CMD_SUCCESS;
359
360 /* This is new/replacement config */
361 pbrms_clear_set_config(pbrms);
362
363 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
364 pbr_map_check(pbrms, true);
365
e5c83d9b
DS
366 return CMD_SUCCESS;
367}
368
bce03323
SW
369DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
370 "no set nexthop-group [NHGNAME$name]",
371 NO_STR
372 "Set for the PBR-MAP\n"
373 "nexthop-group to use\n"
374 "The name of the nexthop-group\n")
375{
376 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
377
378 pbrms_clear_set_config(pbrms);
379
380 return CMD_SUCCESS;
381}
382
e5c83d9b 383DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
bce03323 384 "set nexthop\
9c0fd853
RW
385 <\
386 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
387 |INTERFACE$intf\
388 >\
e429a2a0 389 [nexthop-vrf NAME$vrf_name]",
e5c83d9b
DS
390 "Set for the PBR-MAP\n"
391 "Specify one of the nexthops in this map\n"
392 "v4 Address\n"
393 "v6 Address\n"
394 "Interface to use\n"
9c0fd853 395 "Interface to use\n"
e5c83d9b
DS
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 struct vrf *vrf;
401 struct nexthop nhop;
f143cffa 402 struct nexthop *nh = NULL;
be3b67b5 403
e429a2a0
IR
404 if (vrf_name)
405 vrf = vrf_lookup_by_name(vrf_name);
e5c83d9b
DS
406 else
407 vrf = vrf_lookup_by_id(VRF_DEFAULT);
408
409 if (!vrf) {
0189f722 410 vty_out(vty, "Specified VRF: %s is non-existent\n", vrf_name);
3a9210c2 411 return CMD_WARNING_CONFIG_FAILED;
e5c83d9b
DS
412 }
413
414 memset(&nhop, 0, sizeof(nhop));
415 nhop.vrf_id = vrf->vrf_id;
416
9c0fd853 417 if (intf) {
0189f722
DS
418 struct interface *ifp;
419
420 ifp = if_lookup_by_name_all_vrf(intf);
421 if (!ifp) {
422 vty_out(vty, "Specified Intf %s does not exist\n",
423 intf);
9c0fd853
RW
424 return CMD_WARNING_CONFIG_FAILED;
425 }
0189f722
DS
426 if (ifp->vrf_id != vrf->vrf_id) {
427 struct vrf *actual;
428
429 actual = vrf_lookup_by_id(ifp->vrf_id);
430 vty_out(vty,
431 "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n",
432 ifp->name, vrf->name, actual->name);
433 }
434 nhop.ifindex = ifp->ifindex;
435 nhop.vrf_id = ifp->vrf_id;
9c0fd853
RW
436 }
437
438 if (addr) {
439 if (addr->sa.sa_family == AF_INET) {
440 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
441 if (intf)
442 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
443 else
444 nhop.type = NEXTHOP_TYPE_IPV4;
cafec8da 445 } else {
9c0fd853
RW
446 nhop.gate.ipv6 = addr->sin6.sin6_addr;
447 if (intf)
448 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
449 else {
450 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
451 vty_out(vty,
452 "Specified a v6 LL with no interface, rejecting\n");
453 return CMD_WARNING_CONFIG_FAILED;
454 }
455 nhop.type = NEXTHOP_TYPE_IPV6;
cafec8da 456 }
cafec8da 457 }
9c0fd853
RW
458 } else
459 nhop.type = NEXTHOP_TYPE_IFINDEX;
e5c83d9b
DS
460
461 if (pbrms->nhg)
462 nh = nexthop_exists(pbrms->nhg, &nhop);
e5c83d9b 463
f143cffa
SW
464 if (nh) /* Same config re-entered */
465 goto done;
e5c83d9b 466
f143cffa
SW
467 /* This is new/replacement config */
468 pbrms_clear_set_config(pbrms);
e5c83d9b 469
f143cffa 470 pbr_nht_add_individual_nexthop(pbrms, &nhop);
e5c83d9b 471
f143cffa 472 pbr_map_check(pbrms, true);
e5c83d9b 473
f143cffa 474done:
cb254f41
SW
475 if (nhop.type == NEXTHOP_TYPE_IFINDEX
476 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
477 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
9c0fd853
RW
478 struct interface *ifp;
479
480 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
481 if (ifp)
482 pbr_nht_nexthop_interface_update(ifp);
483 }
484
e5c83d9b
DS
485 return CMD_SUCCESS;
486}
487
bce03323
SW
488DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
489 "no set nexthop\
490 [<\
491 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
492 |INTERFACE$intf\
493 >\
494 [nexthop-vrf NAME$vrf_name]]",
be3b67b5
SW
495 NO_STR
496 "Set for the PBR-MAP\n"
bce03323
SW
497 "Specify one of the nexthops in this map\n"
498 "v4 Address\n"
499 "v6 Address\n"
500 "Interface to use\n"
501 "Interface to use\n"
502 "If the nexthop is in a different vrf tell us\n"
503 "The nexthop-vrf Name\n")
504{
505 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
506
507 pbrms_clear_set_config(pbrms);
508
509 return CMD_SUCCESS;
510}
511
512DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
513 "set vrf <NAME$vrf_name|unchanged>",
514 "Set for the PBR-MAP\n"
be3b67b5
SW
515 "Specify the VRF for this map\n"
516 "The VRF Name\n"
517 "Use the interface's VRF for lookup\n")
518{
519 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
be3b67b5 520
9bf1b0f7 521 /*
f143cffa 522 * If an equivalent set vrf * exists, just return success.
9bf1b0f7 523 */
f143cffa
SW
524 if (vrf_name && pbrms->vrf_lookup
525 && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0)
f3f2c78a 526 return CMD_SUCCESS;
f143cffa 527 else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */
f3f2c78a 528 return CMD_SUCCESS;
9bf1b0f7 529
bce03323
SW
530 if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) {
531 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
532 return CMD_WARNING_CONFIG_FAILED;
533 }
534
f143cffa
SW
535 /* This is new/replacement config */
536 pbrms_clear_set_config(pbrms);
be3b67b5
SW
537
538 if (vrf_name) {
be3b67b5
SW
539 pbrms->vrf_lookup = true;
540 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
541 } else
542 pbrms->vrf_unchanged = true;
543
f143cffa 544 pbr_map_check(pbrms, true);
be3b67b5 545
f3f2c78a 546 return CMD_SUCCESS;
be3b67b5
SW
547}
548
bce03323
SW
549DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
550 "no set vrf [<NAME$vrf_name|unchanged>]",
551 NO_STR
552 "Set for the PBR-MAP\n"
553 "Specify the VRF for this map\n"
554 "The VRF Name\n"
555 "Use the interface's VRF for lookup\n")
556{
557 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
558
559 pbrms_clear_set_config(pbrms);
560
561 return CMD_SUCCESS;
562}
563
e5c83d9b
DS
564DEFPY (pbr_policy,
565 pbr_policy_cmd,
17f8c652 566 "[no] pbr-policy PBRMAP$mapname",
e5c83d9b
DS
567 NO_STR
568 "Policy to use\n"
569 "Name of the pbr-map to apply\n")
570{
571 VTY_DECLVAR_CONTEXT(interface, ifp);
572 struct pbr_map *pbrm, *old_pbrm;
573 struct pbr_interface *pbr_ifp = ifp->info;
574
6eb499b0 575 old_pbrm = NULL;
e5c83d9b
DS
576 pbrm = pbrm_find(mapname);
577
b13e5ad6 578 if (!pbr_ifp) {
d6416967
QY
579 /* we don't want one and we don't have one, so... */
580 if (no)
581 return CMD_SUCCESS;
582
583 /* Some one could have fat fingered the interface name */
b13e5ad6
DS
584 pbr_ifp = pbr_if_new(ifp);
585 }
586
e5c83d9b
DS
587 if (no) {
588 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
5f504f14 589 pbr_ifp->mapname[0] = '\0';
e5c83d9b
DS
590 if (pbrm)
591 pbr_map_interface_delete(pbrm, ifp);
592 }
593 } else {
5f504f14
QY
594 if (strcmp(pbr_ifp->mapname, "") != 0) {
595 old_pbrm = pbrm_find(pbr_ifp->mapname);
6eb499b0
DS
596
597 /*
598 * So if we have an old pbrm we should only
599 * delete it if we are actually deleting and
600 * moving to a new pbrm
601 */
602 if (old_pbrm && old_pbrm != pbrm)
5f504f14 603 pbr_map_interface_delete(old_pbrm, ifp);
e5c83d9b 604 }
5f504f14
QY
605 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
606 "%s", mapname);
6eb499b0
DS
607
608 /*
609 * So only reinstall if the old_pbrm and this pbrm are
610 * different.
611 */
612 if (pbrm && pbrm != old_pbrm)
5f504f14 613 pbr_map_add_interface(pbrm, ifp);
e5c83d9b
DS
614 }
615
616 return CMD_SUCCESS;
617}
618
619DEFPY (show_pbr,
620 show_pbr_cmd,
ef18ed6e 621 "show pbr",
e5c83d9b 622 SHOW_STR
24a21176 623 PBR_STR)
e5c83d9b
DS
624{
625 pbr_nht_write_table_range(vty);
626 pbr_nht_write_rule_range(vty);
627
628 return CMD_SUCCESS;
629}
630
fcf29c69
DS
631static void
632pbrms_nexthop_group_write_individual_nexthop(
633 struct vty *vty, const struct pbr_map_sequence *pbrms)
634{
635 struct pbr_nexthop_group_cache find;
636 struct pbr_nexthop_group_cache *pnhgc;
637 struct pbr_nexthop_cache lookup;
638 struct pbr_nexthop_cache *pnhc;
639
fcf29c69
DS
640 memset(&find, 0, sizeof(find));
641 strlcpy(find.name, pbrms->internal_nhg_name, sizeof(find.name));
642
643 pnhgc = hash_lookup(pbr_nhg_hash, &find);
644 assert(pnhgc);
645
734bf907 646 lookup.nexthop = *pbrms->nhg->nexthop;
fcf29c69 647 pnhc = hash_lookup(pnhgc->nhh, &lookup);
7cbdabff
DS
648
649 nexthop_group_write_nexthop_simple(
650 vty, pbrms->nhg->nexthop,
734bf907
DS
651 pnhc->nexthop.ifindex != 0 ? pnhc->intf_name : NULL);
652 if (pnhc->nexthop.vrf_id != VRF_DEFAULT)
fcf29c69
DS
653 vty_out(vty, " nexthop-vrf %s", pnhc->vrf_name);
654
655 vty_out(vty, "\n");
656}
657
1eaa8361
SW
658static void vty_show_pbrms(struct vty *vty,
659 const struct pbr_map_sequence *pbrms, bool detail)
660{
1eaa8361
SW
661 char rbuf[64];
662
663 if (pbrms->reason)
664 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
3259cde6
SW
665
666 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
667
668 if (detail)
b740126d 669 vty_out(vty, " Installed: %" PRIu64 "(%u) Reason: %s\n",
3259cde6
SW
670 pbrms->installed, pbrms->unique,
671 pbrms->reason ? rbuf : "Valid");
672 else
b740126d 673 vty_out(vty, " Installed: %s Reason: %s\n",
3259cde6
SW
674 pbrms->installed ? "yes" : "no",
675 pbrms->reason ? rbuf : "Valid");
1eaa8361
SW
676
677 if (pbrms->src)
2dbe669b 678 vty_out(vty, " SRC Match: %pFX\n", pbrms->src);
1eaa8361 679 if (pbrms->dst)
2dbe669b 680 vty_out(vty, " DST Match: %pFX\n", pbrms->dst);
01f23aff
WC
681 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
682 vty_out(vty, " DSCP Match: %u\n",
683 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
684 if (pbrms->dsfield & PBR_DSFIELD_ECN)
685 vty_out(vty, " ECN Match: %u\n",
686 pbrms->dsfield & PBR_DSFIELD_ECN);
1eaa8361 687 if (pbrms->mark)
b740126d 688 vty_out(vty, " MARK Match: %u\n", pbrms->mark);
1eaa8361
SW
689
690 if (pbrms->nhgrp_name) {
b740126d 691 vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
add5e0a4 692
3259cde6 693 if (detail)
b740126d
SW
694 vty_out(vty,
695 " Installed: %u(%d) Tableid: %d\n",
3259cde6 696 pbrms->nhs_installed,
add5e0a4
SW
697 pbr_nht_get_installed(pbrms->nhgrp_name),
698 pbr_nht_get_table(pbrms->nhgrp_name));
3259cde6 699 else
b740126d 700 vty_out(vty, " Installed: %s Tableid: %d\n",
add5e0a4
SW
701 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
702 : "no",
703 pbr_nht_get_table(pbrms->nhgrp_name));
704
1eaa8361 705 } else if (pbrms->nhg) {
b740126d 706 vty_out(vty, " ");
fcf29c69 707 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
3259cde6 708 if (detail)
b740126d
SW
709 vty_out(vty,
710 " Installed: %u(%d) Tableid: %d\n",
3259cde6
SW
711 pbrms->nhs_installed,
712 pbr_nht_get_installed(pbrms->internal_nhg_name),
713 pbr_nht_get_table(pbrms->internal_nhg_name));
714 else
b740126d 715 vty_out(vty, " Installed: %s Tableid: %d\n",
3259cde6
SW
716 pbr_nht_get_installed(pbrms->internal_nhg_name)
717 ? "yes"
718 : "no",
719 pbr_nht_get_table(pbrms->internal_nhg_name));
720
1eaa8361 721 } else if (pbrms->vrf_unchanged) {
b740126d 722 vty_out(vty, " VRF Unchanged (use interface vrf)\n");
1eaa8361 723 } else if (pbrms->vrf_lookup) {
b740126d 724 vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name);
1eaa8361 725 } else {
b740126d 726 vty_out(vty, " Nexthop-Group: Unknown Installed: no\n");
1eaa8361
SW
727 }
728}
729
1a8cafe1
WC
730static void vty_json_pbrms(json_object *j, struct vty *vty,
731 const struct pbr_map_sequence *pbrms)
732{
81c0078e 733 json_object *jpbrm, *nexthop_group;
1a8cafe1
WC
734 char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
735 : pbrms->internal_nhg_name;
736 char buf[PREFIX_STRLEN];
737 char rbuf[64];
738
739 jpbrm = json_object_new_object();
740
81c0078e
WC
741 json_object_int_add(jpbrm, "id", pbrms->unique);
742
1a8cafe1
WC
743 if (pbrms->reason)
744 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
745
746 json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
747 json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
1a8cafe1 748 json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
3e81618d 749 json_object_boolean_add(jpbrm, "installed",
1a8cafe1 750 pbr_nht_get_installed(nhg_name));
81c0078e
WC
751 json_object_string_add(jpbrm, "installedReason",
752 pbrms->reason ? rbuf : "Valid");
1a8cafe1 753
81c0078e 754 if (nhg_name) {
1a8cafe1
WC
755 nexthop_group = json_object_new_object();
756
3e81618d 757 json_object_int_add(nexthop_group, "tableId",
1a8cafe1 758 pbr_nht_get_table(nhg_name));
81c0078e 759 json_object_string_add(nexthop_group, "name", nhg_name);
3e81618d 760 json_object_boolean_add(nexthop_group, "installed",
1a8cafe1 761 pbr_nht_get_installed(nhg_name));
3e81618d 762 json_object_int_add(nexthop_group, "installedInternally",
81c0078e 763 pbrms->nhs_installed);
1a8cafe1
WC
764
765 json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
1a8cafe1
WC
766 }
767
81c0078e
WC
768 if (pbrms->vrf_lookup)
769 json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
1a8cafe1 770
81c0078e
WC
771 if (pbrms->src)
772 json_object_string_add(
773 jpbrm, "matchSrc",
774 prefix2str(pbrms->src, buf, sizeof(buf)));
775 if (pbrms->dst)
776 json_object_string_add(
777 jpbrm, "matchDst",
778 prefix2str(pbrms->dst, buf, sizeof(buf)));
779 if (pbrms->mark)
780 json_object_int_add(jpbrm, "matchMark", pbrms->mark);
d301f153
WC
781 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
782 json_object_int_add(jpbrm, "matchDscp",
783 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
784 if (pbrms->dsfield & PBR_DSFIELD_ECN)
785 json_object_int_add(jpbrm, "matchEcn",
786 pbrms->dsfield & PBR_DSFIELD_ECN);
1a8cafe1
WC
787
788 json_object_array_add(j, jpbrm);
789}
790
1eaa8361
SW
791static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
792 bool detail)
793{
794 struct pbr_map_sequence *pbrms;
795 struct listnode *node;
796
1ce24b9b
SW
797 vty_out(vty, " pbr-map %s valid: %s\n", pbrm->name,
798 pbrm->valid ? "yes" : "no");
1eaa8361
SW
799
800 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
801 vty_show_pbrms(vty, pbrms, detail);
802}
803
1a8cafe1
WC
804static void vty_json_pbr_map(json_object *j, struct vty *vty,
805 const struct pbr_map *pbrm)
806{
807 struct pbr_map_sequence *pbrms;
808 struct listnode *node;
809 json_object *jpbrms;
810
811 json_object_string_add(j, "name", pbrm->name);
3e81618d 812 json_object_boolean_add(j, "valid", pbrm->valid);
1a8cafe1
WC
813
814 jpbrms = json_object_new_array();
815
816 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
817 vty_json_pbrms(jpbrms, vty, pbrms);
818
f9368f89 819 json_object_object_add(j, "policies", jpbrms);
1a8cafe1
WC
820}
821
e5c83d9b
DS
822DEFPY (show_pbr_map,
823 show_pbr_map_cmd,
1a8cafe1 824 "show pbr map [NAME$name] [detail$detail|json$json]",
e5c83d9b 825 SHOW_STR
24a21176 826 PBR_STR
e5c83d9b
DS
827 "PBR Map\n"
828 "PBR Map Name\n"
1a8cafe1
WC
829 "Detailed information\n"
830 JSON_STR)
e5c83d9b 831{
e5c83d9b 832 struct pbr_map *pbrm;
1a8cafe1
WC
833 json_object *j = NULL;
834
835 if (json)
dadba1a2 836 j = json_object_new_array();
e5c83d9b
DS
837
838 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
1a8cafe1 839 json_object *this_map = NULL;
e5c83d9b
DS
840 if (name && strcmp(name, pbrm->name) != 0)
841 continue;
842
1a8cafe1
WC
843 if (j)
844 this_map = json_object_new_object();
845
846 if (this_map) {
847 vty_json_pbr_map(this_map, vty, pbrm);
848
dadba1a2 849 json_object_array_add(j, this_map);
1a8cafe1
WC
850 continue;
851 }
852
1eaa8361 853 vty_show_pbr_map(vty, pbrm, detail);
e5c83d9b 854 }
1a8cafe1
WC
855
856 if (j) {
857 vty_out(vty, "%s\n",
858 json_object_to_json_string_ext(
859 j, JSON_C_TO_STRING_PRETTY));
860 json_object_free(j);
861 }
862
e5c83d9b
DS
863 return CMD_SUCCESS;
864}
865
866DEFPY(show_pbr_nexthop_group,
867 show_pbr_nexthop_group_cmd,
010dd8ed 868 "show pbr nexthop-groups [WORD$word] [json$json]",
e5c83d9b 869 SHOW_STR
24a21176 870 PBR_STR
e5c83d9b 871 "Nexthop Groups\n"
010dd8ed
WC
872 "Optional Name of the nexthop group\n"
873 JSON_STR)
e5c83d9b 874{
010dd8ed
WC
875 json_object *j = NULL;
876
877 if (json)
dadba1a2 878 j = json_object_new_array();
010dd8ed
WC
879
880 if (j) {
881 pbr_nht_json_nexthop_group(j, word);
882
883 vty_out(vty, "%s\n",
884 json_object_to_json_string_ext(
885 j, JSON_C_TO_STRING_PRETTY));
886
887 json_object_free(j);
888 } else
889 pbr_nht_show_nexthop_group(vty, word);
890
e5c83d9b
DS
891
892 return CMD_SUCCESS;
893}
894
895DEFPY (show_pbr_interface,
896 show_pbr_interface_cmd,
7a7b0c13 897 "show pbr interface [NAME$name] [json$json]",
e5c83d9b 898 SHOW_STR
24a21176 899 PBR_STR
e5c83d9b 900 "PBR Interface\n"
7a7b0c13
WC
901 "PBR Interface Name\n"
902 JSON_STR)
e5c83d9b 903{
d3765386 904 struct interface *ifp;
e5c83d9b
DS
905 struct vrf *vrf;
906 struct pbr_interface *pbr_ifp;
7a7b0c13
WC
907 json_object *j = NULL;
908
909 if (json)
dadba1a2 910 j = json_object_new_array();
e5c83d9b
DS
911
912 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
913 FOR_ALL_INTERFACES(vrf, ifp) {
914 struct pbr_map *pbrm;
7a7b0c13
WC
915 json_object *this_iface = NULL;
916
917 if (j)
918 this_iface = json_object_new_object();
e5c83d9b 919
c195ae78
DS
920 if (!ifp->info) {
921 json_object_free(this_iface);
1c33fb1d 922 continue;
c195ae78 923 }
1c33fb1d 924
c195ae78
DS
925 if (name && strcmp(ifp->name, name) != 0) {
926 json_object_free(this_iface);
e5c83d9b 927 continue;
c195ae78 928 }
e5c83d9b
DS
929
930 pbr_ifp = ifp->info;
931
c195ae78
DS
932 if (strcmp(pbr_ifp->mapname, "") == 0) {
933 json_object_free(this_iface);
e5c83d9b 934 continue;
c195ae78 935 }
e5c83d9b
DS
936
937 pbrm = pbrm_find(pbr_ifp->mapname);
7a7b0c13
WC
938
939 if (this_iface) {
940 json_object_string_add(this_iface, "name",
941 ifp->name);
942 json_object_int_add(this_iface, "index",
943 ifp->ifindex);
944 json_object_string_add(this_iface, "policy",
945 pbr_ifp->mapname);
3e81618d 946 json_object_boolean_add(this_iface, "valid",
7a7b0c13
WC
947 pbrm);
948
dadba1a2 949 json_object_array_add(j, this_iface);
7a7b0c13
WC
950 continue;
951 }
952
e5c83d9b
DS
953 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
954 ifp->ifindex, pbr_ifp->mapname);
955 if (!pbrm)
956 vty_out(vty, " (map doesn't exist)");
957 vty_out(vty, "\n");
958 }
959 }
960
7a7b0c13
WC
961 if (j) {
962 vty_out(vty, "%s\n",
963 json_object_to_json_string_ext(
964 j, JSON_C_TO_STRING_PRETTY));
965 json_object_free(j);
966 }
967
e5c83d9b
DS
968 return CMD_SUCCESS;
969}
970
e14f43cc 971/* PBR debugging CLI ------------------------------------------------------- */
e14f43cc 972
62b346ee 973static struct cmd_node debug_node = {
f4b8291f 974 .name = "debug",
62b346ee
DL
975 .node = DEBUG_NODE,
976 .prompt = "",
612c2c15 977 .config_write = pbr_debug_config_write,
62b346ee 978};
e14f43cc
QY
979
980DEFPY(debug_pbr,
981 debug_pbr_cmd,
982 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
983 NO_STR
984 DEBUG_STR
24a21176 985 PBR_STR
e14f43cc
QY
986 "Policy maps\n"
987 "PBRD <-> Zebra communications\n"
988 "Nexthop tracking\n"
989 "Events\n")
990{
991 uint32_t mode = DEBUG_NODE2MODE(vty->node);
992
993 if (map)
994 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
995 if (zebra)
996 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
997 if (nht)
998 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
999 if (events)
1000 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
1001
1002 /* no specific debug --> act on all of them */
1003 if (strmatch(argv[argc - 1]->text, "pbr"))
1004 pbr_debug_set_all(mode, !no);
1005
1006 return CMD_SUCCESS;
1007}
1008
1009DEFUN_NOSH(show_debugging_pbr,
1010 show_debugging_pbr_cmd,
1011 "show debugging [pbr]",
1012 SHOW_STR
1013 DEBUG_STR
24a21176 1014 PBR_STR)
e14f43cc
QY
1015{
1016 vty_out(vty, "PBR debugging status:\n");
1017
1018 pbr_debug_config_write_helper(vty, false);
1019
1020 return CMD_SUCCESS;
1021}
1022
e14f43cc
QY
1023/* ------------------------------------------------------------------------- */
1024
1025
612c2c15 1026static int pbr_interface_config_write(struct vty *vty);
e5c83d9b 1027static struct cmd_node interface_node = {
f4b8291f 1028 .name = "interface",
62b346ee 1029 .node = INTERFACE_NODE,
24389580 1030 .parent_node = CONFIG_NODE,
62b346ee 1031 .prompt = "%s(config-if)# ",
612c2c15 1032 .config_write = pbr_interface_config_write,
e5c83d9b
DS
1033};
1034
1035static int pbr_interface_config_write(struct vty *vty)
1036{
1037 struct interface *ifp;
1038 struct vrf *vrf;
1039
1040 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1041 FOR_ALL_INTERFACES (vrf, ifp) {
1042 if (vrf->vrf_id == VRF_DEFAULT)
1043 vty_frame(vty, "interface %s\n", ifp->name);
1044 else
1045 vty_frame(vty, "interface %s vrf %s\n",
1046 ifp->name, vrf->name);
1047
91e5b43a
RW
1048 if (ifp->desc)
1049 vty_out(vty, " description %s\n", ifp->desc);
1050
e5c83d9b
DS
1051 pbr_map_write_interfaces(vty, ifp);
1052
1053 vty_endframe(vty, "!\n");
1054 }
1055 }
1056
1057 return 1;
1058}
1059
612c2c15 1060static int pbr_vty_map_config_write(struct vty *vty);
e5c83d9b 1061/* PBR map node structure. */
62b346ee 1062static struct cmd_node pbr_map_node = {
f4b8291f 1063 .name = "pbr-map",
62b346ee 1064 .node = PBRMAP_NODE,
24389580 1065 .parent_node = CONFIG_NODE,
62b346ee 1066 .prompt = "%s(config-pbr-map)# ",
612c2c15 1067 .config_write = pbr_vty_map_config_write,
62b346ee 1068};
e5c83d9b
DS
1069
1070static int pbr_vty_map_config_write_sequence(struct vty *vty,
1071 struct pbr_map *pbrm,
1072 struct pbr_map_sequence *pbrms)
1073{
5e44f18f 1074 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
e5c83d9b
DS
1075
1076 if (pbrms->src)
2dbe669b 1077 vty_out(vty, " match src-ip %pFX\n", pbrms->src);
e5c83d9b
DS
1078
1079 if (pbrms->dst)
2dbe669b 1080 vty_out(vty, " match dst-ip %pFX\n", pbrms->dst);
e5c83d9b 1081
01f23aff
WC
1082 if (pbrms->dsfield & PBR_DSFIELD_DSCP)
1083 vty_out(vty, " match dscp %u\n",
1084 (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
1085
1086 if (pbrms->dsfield & PBR_DSFIELD_ECN)
1087 vty_out(vty, " match ecn %u\n",
1088 pbrms->dsfield & PBR_DSFIELD_ECN);
1089
95a9fe02
MM
1090 if (pbrms->mark)
1091 vty_out(vty, " match mark %u\n", pbrms->mark);
1092
be3b67b5
SW
1093 if (pbrms->vrf_unchanged)
1094 vty_out(vty, " set vrf unchanged\n");
1095
1096 if (pbrms->vrf_lookup)
1097 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
1098
e5c83d9b 1099 if (pbrms->nhgrp_name)
7dce96f0 1100 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
e5c83d9b
DS
1101
1102 if (pbrms->nhg) {
7dce96f0 1103 vty_out(vty, " set ");
fcf29c69 1104 pbrms_nexthop_group_write_individual_nexthop(vty, pbrms);
e5c83d9b
DS
1105 }
1106
5e44f18f 1107 vty_out(vty, "!\n");
e5c83d9b
DS
1108 return 1;
1109}
1110
1111static int pbr_vty_map_config_write(struct vty *vty)
1112{
1113 struct pbr_map *pbrm;
1114
1115 pbr_nht_write_table_range(vty);
1116 pbr_nht_write_rule_range(vty);
1117
1118 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
1119 struct pbr_map_sequence *pbrms;
1120 struct listnode *node;
1121
d3765386 1122 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
e5c83d9b 1123 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
e5c83d9b
DS
1124 }
1125
1126 return 1;
1127}
1128
17f8c652
DS
1129static void pbr_map_completer(vector comps, struct cmd_token *token)
1130{
1131 struct pbr_map *pbrm;
1132
1133 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
1134 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
1135}
1136
1137static const struct cmd_variable_handler pbr_map_name[] = {
1138 {
1139 .tokenname = "PBRMAP", .completions = pbr_map_completer,
1140 },
1141 {
1142 .completions = NULL
1143 }
1144};
1145
e5c83d9b
DS
1146void pbr_vty_init(void)
1147{
17f8c652
DS
1148 cmd_variable_handler_register(pbr_map_name);
1149
612c2c15 1150 install_node(&interface_node);
e5c83d9b
DS
1151 if_cmd_init();
1152
612c2c15 1153 install_node(&pbr_map_node);
e5c83d9b 1154
e14f43cc 1155 /* debug */
612c2c15 1156 install_node(&debug_node);
eed041e8 1157 install_element(ENABLE_NODE, &debug_pbr_cmd);
e14f43cc 1158 install_element(CONFIG_NODE, &debug_pbr_cmd);
dd73744d 1159 install_element(ENABLE_NODE, &show_debugging_pbr_cmd);
e14f43cc 1160
e5c83d9b
DS
1161 install_default(PBRMAP_NODE);
1162
1163 install_element(CONFIG_NODE, &pbr_map_cmd);
1164 install_element(CONFIG_NODE, &no_pbr_map_cmd);
7bec514c 1165 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
b246eb8a 1166 install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);
e5c83d9b 1167 install_element(INTERFACE_NODE, &pbr_policy_cmd);
e5c83d9b
DS
1168 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
1169 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
01f23aff
WC
1170 install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
1171 install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
95a9fe02 1172 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
e5c83d9b 1173 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
bce03323 1174 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
e5c83d9b 1175 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
bce03323 1176 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_cmd);
be3b67b5 1177 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
bce03323 1178 install_element(PBRMAP_NODE, &no_pbr_map_vrf_cmd);
e5c83d9b
DS
1179 install_element(VIEW_NODE, &show_pbr_cmd);
1180 install_element(VIEW_NODE, &show_pbr_map_cmd);
1181 install_element(VIEW_NODE, &show_pbr_interface_cmd);
1182 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
e5c83d9b 1183}