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