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