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