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