]> git.proxmox.com Git - mirror_frr.git/blob - pbrd/pbr_vty.c
Merge pull request #6054 from sarav511/dr2ndr
[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 pbrms->family = prefix->family;
141
142 if (!no) {
143 if (pbrms->src) {
144 if (prefix_same(pbrms->src, prefix))
145 return CMD_SUCCESS;
146 } else
147 pbrms->src = prefix_new();
148
149 prefix_copy(pbrms->src, prefix);
150 } else
151 prefix_free(&pbrms->src);
152
153 pbr_map_check(pbrms, true);
154
155 return CMD_SUCCESS;
156 }
157
158 DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
159 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
160 NO_STR
161 "Match the rest of the command\n"
162 "Choose the dst ip or ipv6 prefix to use\n"
163 "v4 Prefix\n"
164 "v6 Prefix\n")
165 {
166 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
167
168 pbrms->family = prefix->family;
169
170 if (!no) {
171 if (pbrms->dst) {
172 if (prefix_same(pbrms->dst, prefix))
173 return CMD_SUCCESS;
174 } else
175 pbrms->dst = prefix_new();
176
177 prefix_copy(pbrms->dst, prefix);
178 } else
179 prefix_free(&pbrms->dst);
180
181 pbr_map_check(pbrms, true);
182
183 return CMD_SUCCESS;
184 }
185
186 DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
187 "[no] match mark (1-4294967295)$mark",
188 NO_STR
189 "Match the rest of the command\n"
190 "Choose the mark value to use\n"
191 "mark\n")
192 {
193 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
194
195 #ifndef GNU_LINUX
196 vty_out(vty, "pbr marks are not supported on this platform");
197 return CMD_WARNING_CONFIG_FAILED;
198 #endif
199
200 if (!no) {
201 if (pbrms->mark)
202 if (pbrms->mark == (uint32_t)mark)
203 return CMD_SUCCESS;
204
205 pbrms->mark = (uint32_t)mark;
206 } else
207 pbrms->mark = 0;
208
209 pbr_map_check(pbrms, true);
210
211 return CMD_SUCCESS;
212 }
213
214 static void pbrms_clear_set_vrf_config(struct pbr_map_sequence *pbrms)
215 {
216 if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
217 pbr_map_delete_vrf(pbrms);
218 pbrms->vrf_name[0] = '\0';
219 pbrms->vrf_lookup = false;
220 pbrms->vrf_unchanged = false;
221 }
222 }
223
224 static void pbrms_clear_set_nhg_config(struct pbr_map_sequence *pbrms)
225 {
226 if (pbrms->nhgrp_name)
227 pbr_map_delete_nexthops(pbrms);
228 }
229
230 static void pbrms_clear_set_nexthop_config(struct pbr_map_sequence *pbrms)
231 {
232 if (pbrms->nhg)
233 pbr_nht_delete_individual_nexthop(pbrms);
234 }
235
236 static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms)
237 {
238 pbrms_clear_set_vrf_config(pbrms);
239 pbrms_clear_set_nhg_config(pbrms);
240 pbrms_clear_set_nexthop_config(pbrms);
241
242 pbrms->nhs_installed = false;
243 }
244
245 DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
246 "set nexthop-group NHGNAME$name",
247 "Set for the PBR-MAP\n"
248 "nexthop-group to use\n"
249 "The name of the nexthop-group\n")
250 {
251 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
252 struct nexthop_group_cmd *nhgc;
253
254 nhgc = nhgc_find(name);
255 if (!nhgc) {
256 vty_out(vty, "Specified nexthop-group %s does not exist\n",
257 name);
258 vty_out(vty,
259 "PBR-MAP will not be applied until it is created\n");
260 }
261
262 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
263 return CMD_SUCCESS;
264
265 /* This is new/replacement config */
266 pbrms_clear_set_config(pbrms);
267
268 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
269 pbr_map_check(pbrms, true);
270
271 return CMD_SUCCESS;
272 }
273
274 DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd,
275 "no set nexthop-group [NHGNAME$name]",
276 NO_STR
277 "Set for the PBR-MAP\n"
278 "nexthop-group to use\n"
279 "The name of the nexthop-group\n")
280 {
281 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
282
283 pbrms_clear_set_config(pbrms);
284
285 return CMD_SUCCESS;
286 }
287
288 DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
289 "set nexthop\
290 <\
291 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
292 |INTERFACE$intf\
293 >\
294 [nexthop-vrf NAME$vrf_name]",
295 "Set for the PBR-MAP\n"
296 "Specify one of the nexthops in this map\n"
297 "v4 Address\n"
298 "v6 Address\n"
299 "Interface to use\n"
300 "Interface to use\n"
301 "If the nexthop is in a different vrf tell us\n"
302 "The nexthop-vrf Name\n")
303 {
304 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
305 struct vrf *vrf;
306 struct nexthop nhop;
307 struct nexthop *nh = NULL;
308
309 if (vrf_name)
310 vrf = vrf_lookup_by_name(vrf_name);
311 else
312 vrf = vrf_lookup_by_id(VRF_DEFAULT);
313
314 if (!vrf) {
315 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
316 return CMD_WARNING_CONFIG_FAILED;
317 }
318
319 memset(&nhop, 0, sizeof(nhop));
320 nhop.vrf_id = vrf->vrf_id;
321
322 if (intf) {
323 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
324 if (nhop.ifindex == IFINDEX_INTERNAL) {
325 vty_out(vty,
326 "Specified Intf %s does not exist in vrf: %s\n",
327 intf, vrf->name);
328 return CMD_WARNING_CONFIG_FAILED;
329 }
330 }
331
332 if (addr) {
333 if (addr->sa.sa_family == AF_INET) {
334 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
335 if (intf)
336 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
337 else
338 nhop.type = NEXTHOP_TYPE_IPV4;
339 } else {
340 nhop.gate.ipv6 = addr->sin6.sin6_addr;
341 if (intf)
342 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
343 else {
344 if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
345 vty_out(vty,
346 "Specified a v6 LL with no interface, rejecting\n");
347 return CMD_WARNING_CONFIG_FAILED;
348 }
349 nhop.type = NEXTHOP_TYPE_IPV6;
350 }
351 }
352 } else
353 nhop.type = NEXTHOP_TYPE_IFINDEX;
354
355 if (pbrms->nhg)
356 nh = nexthop_exists(pbrms->nhg, &nhop);
357
358 if (nh) /* Same config re-entered */
359 goto done;
360
361 /* This is new/replacement config */
362 pbrms_clear_set_config(pbrms);
363
364 pbr_nht_add_individual_nexthop(pbrms, &nhop);
365
366 pbr_map_check(pbrms, true);
367
368 done:
369 if (nhop.type == NEXTHOP_TYPE_IFINDEX
370 || (nhop.type == NEXTHOP_TYPE_IPV6_IFINDEX
371 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6))) {
372 struct interface *ifp;
373
374 ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
375 if (ifp)
376 pbr_nht_nexthop_interface_update(ifp);
377 }
378
379 return CMD_SUCCESS;
380 }
381
382 DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd,
383 "no set nexthop\
384 [<\
385 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
386 |INTERFACE$intf\
387 >\
388 [nexthop-vrf NAME$vrf_name]]",
389 NO_STR
390 "Set for the PBR-MAP\n"
391 "Specify one of the nexthops in this map\n"
392 "v4 Address\n"
393 "v6 Address\n"
394 "Interface to use\n"
395 "Interface to use\n"
396 "If the nexthop is in a different vrf tell us\n"
397 "The nexthop-vrf Name\n")
398 {
399 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
400
401 pbrms_clear_set_config(pbrms);
402
403 return CMD_SUCCESS;
404 }
405
406 DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
407 "set vrf <NAME$vrf_name|unchanged>",
408 "Set for the PBR-MAP\n"
409 "Specify the VRF for this map\n"
410 "The VRF Name\n"
411 "Use the interface's VRF for lookup\n")
412 {
413 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
414
415 /*
416 * If an equivalent set vrf * exists, just return success.
417 */
418 if (vrf_name && pbrms->vrf_lookup
419 && strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) == 0)
420 return CMD_SUCCESS;
421 else if (!vrf_name && pbrms->vrf_unchanged) /* Unchanged already set */
422 return CMD_SUCCESS;
423
424 if (vrf_name && !pbr_vrf_lookup_by_name(vrf_name)) {
425 vty_out(vty, "Specified: %s is non-existent\n", vrf_name);
426 return CMD_WARNING_CONFIG_FAILED;
427 }
428
429 /* This is new/replacement config */
430 pbrms_clear_set_config(pbrms);
431
432 if (vrf_name) {
433 pbrms->vrf_lookup = true;
434 strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
435 } else
436 pbrms->vrf_unchanged = true;
437
438 pbr_map_check(pbrms, true);
439
440 return CMD_SUCCESS;
441 }
442
443 DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd,
444 "no set vrf [<NAME$vrf_name|unchanged>]",
445 NO_STR
446 "Set for the PBR-MAP\n"
447 "Specify the VRF for this map\n"
448 "The VRF Name\n"
449 "Use the interface's VRF for lookup\n")
450 {
451 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
452
453 pbrms_clear_set_config(pbrms);
454
455 return CMD_SUCCESS;
456 }
457
458 DEFPY (pbr_policy,
459 pbr_policy_cmd,
460 "[no] pbr-policy PBRMAP$mapname",
461 NO_STR
462 "Policy to use\n"
463 "Name of the pbr-map to apply\n")
464 {
465 VTY_DECLVAR_CONTEXT(interface, ifp);
466 struct pbr_map *pbrm, *old_pbrm;
467 struct pbr_interface *pbr_ifp = ifp->info;
468
469 old_pbrm = NULL;
470 pbrm = pbrm_find(mapname);
471
472 if (!pbr_ifp) {
473 /* we don't want one and we don't have one, so... */
474 if (no)
475 return CMD_SUCCESS;
476
477 /* Some one could have fat fingered the interface name */
478 pbr_ifp = pbr_if_new(ifp);
479 }
480
481 if (no) {
482 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
483 pbr_ifp->mapname[0] = '\0';
484 if (pbrm)
485 pbr_map_interface_delete(pbrm, ifp);
486 }
487 } else {
488 if (strcmp(pbr_ifp->mapname, "") != 0) {
489 old_pbrm = pbrm_find(pbr_ifp->mapname);
490
491 /*
492 * So if we have an old pbrm we should only
493 * delete it if we are actually deleting and
494 * moving to a new pbrm
495 */
496 if (old_pbrm && old_pbrm != pbrm)
497 pbr_map_interface_delete(old_pbrm, ifp);
498 }
499 snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname),
500 "%s", mapname);
501
502 /*
503 * So only reinstall if the old_pbrm and this pbrm are
504 * different.
505 */
506 if (pbrm && pbrm != old_pbrm)
507 pbr_map_add_interface(pbrm, ifp);
508 }
509
510 return CMD_SUCCESS;
511 }
512
513 DEFPY (show_pbr,
514 show_pbr_cmd,
515 "show pbr",
516 SHOW_STR
517 PBR_STR)
518 {
519 pbr_nht_write_table_range(vty);
520 pbr_nht_write_rule_range(vty);
521
522 return CMD_SUCCESS;
523 }
524
525 static void vty_show_pbrms(struct vty *vty,
526 const struct pbr_map_sequence *pbrms, bool detail)
527 {
528 char buf[PREFIX_STRLEN];
529 char rbuf[64];
530
531 if (pbrms->reason)
532 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
533
534 vty_out(vty, " Seq: %u rule: %u\n", pbrms->seqno, pbrms->ruleno);
535
536 if (detail)
537 vty_out(vty, " Installed: %" PRIu64 "(%u) Reason: %s\n",
538 pbrms->installed, pbrms->unique,
539 pbrms->reason ? rbuf : "Valid");
540 else
541 vty_out(vty, " Installed: %s Reason: %s\n",
542 pbrms->installed ? "yes" : "no",
543 pbrms->reason ? rbuf : "Valid");
544
545 if (pbrms->src)
546 vty_out(vty, " SRC Match: %s\n",
547 prefix2str(pbrms->src, buf, sizeof(buf)));
548 if (pbrms->dst)
549 vty_out(vty, " DST Match: %s\n",
550 prefix2str(pbrms->dst, buf, sizeof(buf)));
551 if (pbrms->mark)
552 vty_out(vty, " MARK Match: %u\n", pbrms->mark);
553
554 if (pbrms->nhgrp_name) {
555 vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name);
556
557 if (detail)
558 vty_out(vty,
559 " Installed: %u(%d) Tableid: %d\n",
560 pbrms->nhs_installed,
561 pbr_nht_get_installed(pbrms->nhgrp_name),
562 pbr_nht_get_table(pbrms->nhgrp_name));
563 else
564 vty_out(vty, " Installed: %s Tableid: %d\n",
565 pbr_nht_get_installed(pbrms->nhgrp_name) ? "yes"
566 : "no",
567 pbr_nht_get_table(pbrms->nhgrp_name));
568
569 } else if (pbrms->nhg) {
570 vty_out(vty, " ");
571 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
572 if (detail)
573 vty_out(vty,
574 " Installed: %u(%d) Tableid: %d\n",
575 pbrms->nhs_installed,
576 pbr_nht_get_installed(pbrms->internal_nhg_name),
577 pbr_nht_get_table(pbrms->internal_nhg_name));
578 else
579 vty_out(vty, " Installed: %s Tableid: %d\n",
580 pbr_nht_get_installed(pbrms->internal_nhg_name)
581 ? "yes"
582 : "no",
583 pbr_nht_get_table(pbrms->internal_nhg_name));
584
585 } else if (pbrms->vrf_unchanged) {
586 vty_out(vty, " VRF Unchanged (use interface vrf)\n");
587 } else if (pbrms->vrf_lookup) {
588 vty_out(vty, " VRF Lookup: %s\n", pbrms->vrf_name);
589 } else {
590 vty_out(vty, " Nexthop-Group: Unknown Installed: no\n");
591 }
592 }
593
594 static void vty_json_pbrms(json_object *j, struct vty *vty,
595 const struct pbr_map_sequence *pbrms)
596 {
597 json_object *jpbrm, *nexthop_group;
598 char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
599 : pbrms->internal_nhg_name;
600 char buf[PREFIX_STRLEN];
601 char rbuf[64];
602
603 jpbrm = json_object_new_object();
604
605 json_object_int_add(jpbrm, "id", pbrms->unique);
606
607 if (pbrms->reason)
608 pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
609
610 json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
611 json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
612 json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
613 json_object_boolean_add(jpbrm, "installed",
614 pbr_nht_get_installed(nhg_name));
615 json_object_string_add(jpbrm, "installedReason",
616 pbrms->reason ? rbuf : "Valid");
617
618 if (nhg_name) {
619 nexthop_group = json_object_new_object();
620
621 json_object_int_add(nexthop_group, "tableId",
622 pbr_nht_get_table(nhg_name));
623 json_object_string_add(nexthop_group, "name", nhg_name);
624 json_object_boolean_add(nexthop_group, "installed",
625 pbr_nht_get_installed(nhg_name));
626 json_object_int_add(nexthop_group, "installedInternally",
627 pbrms->nhs_installed);
628
629 json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
630 }
631
632 if (pbrms->vrf_lookup)
633 json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
634
635 if (pbrms->src)
636 json_object_string_add(
637 jpbrm, "matchSrc",
638 prefix2str(pbrms->src, buf, sizeof(buf)));
639 if (pbrms->dst)
640 json_object_string_add(
641 jpbrm, "matchDst",
642 prefix2str(pbrms->dst, buf, sizeof(buf)));
643 if (pbrms->mark)
644 json_object_int_add(jpbrm, "matchMark", pbrms->mark);
645
646 json_object_array_add(j, jpbrm);
647 }
648
649 static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
650 bool detail)
651 {
652 struct pbr_map_sequence *pbrms;
653 struct listnode *node;
654
655 vty_out(vty, " pbr-map %s valid: %s\n", pbrm->name,
656 pbrm->valid ? "yes" : "no");
657
658 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
659 vty_show_pbrms(vty, pbrms, detail);
660 }
661
662 static void vty_json_pbr_map(json_object *j, struct vty *vty,
663 const struct pbr_map *pbrm)
664 {
665 struct pbr_map_sequence *pbrms;
666 struct listnode *node;
667 json_object *jpbrms;
668
669 json_object_string_add(j, "name", pbrm->name);
670 json_object_boolean_add(j, "valid", pbrm->valid);
671
672 jpbrms = json_object_new_array();
673
674 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
675 vty_json_pbrms(jpbrms, vty, pbrms);
676
677 json_object_object_add(j, "policies", jpbrms);
678 }
679
680 DEFPY (show_pbr_map,
681 show_pbr_map_cmd,
682 "show pbr map [NAME$name] [detail$detail|json$json]",
683 SHOW_STR
684 PBR_STR
685 "PBR Map\n"
686 "PBR Map Name\n"
687 "Detailed information\n"
688 JSON_STR)
689 {
690 struct pbr_map *pbrm;
691 json_object *j = NULL;
692
693 if (json)
694 j = json_object_new_array();
695
696 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
697 json_object *this_map = NULL;
698 if (name && strcmp(name, pbrm->name) != 0)
699 continue;
700
701 if (j)
702 this_map = json_object_new_object();
703
704 if (this_map) {
705 vty_json_pbr_map(this_map, vty, pbrm);
706
707 json_object_array_add(j, this_map);
708 continue;
709 }
710
711 vty_show_pbr_map(vty, pbrm, detail);
712 }
713
714 if (j) {
715 vty_out(vty, "%s\n",
716 json_object_to_json_string_ext(
717 j, JSON_C_TO_STRING_PRETTY));
718 json_object_free(j);
719 }
720
721 return CMD_SUCCESS;
722 }
723
724 DEFPY(show_pbr_nexthop_group,
725 show_pbr_nexthop_group_cmd,
726 "show pbr nexthop-groups [WORD$word] [json$json]",
727 SHOW_STR
728 PBR_STR
729 "Nexthop Groups\n"
730 "Optional Name of the nexthop group\n"
731 JSON_STR)
732 {
733 json_object *j = NULL;
734
735 if (json)
736 j = json_object_new_array();
737
738 if (j) {
739 pbr_nht_json_nexthop_group(j, word);
740
741 vty_out(vty, "%s\n",
742 json_object_to_json_string_ext(
743 j, JSON_C_TO_STRING_PRETTY));
744
745 json_object_free(j);
746 } else
747 pbr_nht_show_nexthop_group(vty, word);
748
749
750 return CMD_SUCCESS;
751 }
752
753 DEFPY (show_pbr_interface,
754 show_pbr_interface_cmd,
755 "show pbr interface [NAME$name] [json$json]",
756 SHOW_STR
757 PBR_STR
758 "PBR Interface\n"
759 "PBR Interface Name\n"
760 JSON_STR)
761 {
762 struct interface *ifp;
763 struct vrf *vrf;
764 struct pbr_interface *pbr_ifp;
765 json_object *j = NULL;
766
767 if (json)
768 j = json_object_new_array();
769
770 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
771 FOR_ALL_INTERFACES(vrf, ifp) {
772 struct pbr_map *pbrm;
773 json_object *this_iface = NULL;
774
775 if (j)
776 this_iface = json_object_new_object();
777
778 if (!ifp->info)
779 continue;
780
781 if (name && strcmp(ifp->name, name) != 0)
782 continue;
783
784 pbr_ifp = ifp->info;
785
786 if (strcmp(pbr_ifp->mapname, "") == 0)
787 continue;
788
789 pbrm = pbrm_find(pbr_ifp->mapname);
790
791 if (this_iface) {
792 json_object_string_add(this_iface, "name",
793 ifp->name);
794 json_object_int_add(this_iface, "index",
795 ifp->ifindex);
796 json_object_string_add(this_iface, "policy",
797 pbr_ifp->mapname);
798 json_object_boolean_add(this_iface, "valid",
799 pbrm);
800
801 json_object_array_add(j, this_iface);
802 continue;
803 }
804
805 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
806 ifp->ifindex, pbr_ifp->mapname);
807 if (!pbrm)
808 vty_out(vty, " (map doesn't exist)");
809 vty_out(vty, "\n");
810 }
811 }
812
813 if (j) {
814 vty_out(vty, "%s\n",
815 json_object_to_json_string_ext(
816 j, JSON_C_TO_STRING_PRETTY));
817 json_object_free(j);
818 }
819
820 return CMD_SUCCESS;
821 }
822
823 /* PBR debugging CLI ------------------------------------------------------- */
824
825 static struct cmd_node debug_node = {
826 .name = "debug",
827 .node = DEBUG_NODE,
828 .prompt = "",
829 .config_write = pbr_debug_config_write,
830 };
831
832 DEFPY(debug_pbr,
833 debug_pbr_cmd,
834 "[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
835 NO_STR
836 DEBUG_STR
837 PBR_STR
838 "Policy maps\n"
839 "PBRD <-> Zebra communications\n"
840 "Nexthop tracking\n"
841 "Events\n")
842 {
843 uint32_t mode = DEBUG_NODE2MODE(vty->node);
844
845 if (map)
846 DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
847 if (zebra)
848 DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
849 if (nht)
850 DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
851 if (events)
852 DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
853
854 /* no specific debug --> act on all of them */
855 if (strmatch(argv[argc - 1]->text, "pbr"))
856 pbr_debug_set_all(mode, !no);
857
858 return CMD_SUCCESS;
859 }
860
861 DEFUN_NOSH(show_debugging_pbr,
862 show_debugging_pbr_cmd,
863 "show debugging [pbr]",
864 SHOW_STR
865 DEBUG_STR
866 PBR_STR)
867 {
868 vty_out(vty, "PBR debugging status:\n");
869
870 pbr_debug_config_write_helper(vty, false);
871
872 return CMD_SUCCESS;
873 }
874
875 /* ------------------------------------------------------------------------- */
876
877
878 static int pbr_interface_config_write(struct vty *vty);
879 static struct cmd_node interface_node = {
880 .name = "interface",
881 .node = INTERFACE_NODE,
882 .parent_node = CONFIG_NODE,
883 .prompt = "%s(config-if)# ",
884 .config_write = pbr_interface_config_write,
885 };
886
887 static int pbr_interface_config_write(struct vty *vty)
888 {
889 struct interface *ifp;
890 struct vrf *vrf;
891
892 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
893 FOR_ALL_INTERFACES (vrf, ifp) {
894 if (vrf->vrf_id == VRF_DEFAULT)
895 vty_frame(vty, "interface %s\n", ifp->name);
896 else
897 vty_frame(vty, "interface %s vrf %s\n",
898 ifp->name, vrf->name);
899
900 if (ifp->desc)
901 vty_out(vty, " description %s\n", ifp->desc);
902
903 pbr_map_write_interfaces(vty, ifp);
904
905 vty_endframe(vty, "!\n");
906 }
907 }
908
909 return 1;
910 }
911
912 static int pbr_vty_map_config_write(struct vty *vty);
913 /* PBR map node structure. */
914 static struct cmd_node pbr_map_node = {
915 .name = "pbr-map",
916 .node = PBRMAP_NODE,
917 .parent_node = CONFIG_NODE,
918 .prompt = "%s(config-pbr-map)# ",
919 .config_write = pbr_vty_map_config_write,
920 };
921
922 static int pbr_vty_map_config_write_sequence(struct vty *vty,
923 struct pbr_map *pbrm,
924 struct pbr_map_sequence *pbrms)
925 {
926 char buff[PREFIX_STRLEN];
927
928 vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
929
930 if (pbrms->src)
931 vty_out(vty, " match src-ip %s\n",
932 prefix2str(pbrms->src, buff, sizeof(buff)));
933
934 if (pbrms->dst)
935 vty_out(vty, " match dst-ip %s\n",
936 prefix2str(pbrms->dst, buff, sizeof(buff)));
937
938 if (pbrms->mark)
939 vty_out(vty, " match mark %u\n", pbrms->mark);
940
941 if (pbrms->vrf_unchanged)
942 vty_out(vty, " set vrf unchanged\n");
943
944 if (pbrms->vrf_lookup)
945 vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
946
947 if (pbrms->nhgrp_name)
948 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
949
950 if (pbrms->nhg) {
951 vty_out(vty, " set ");
952 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
953 }
954
955 vty_out(vty, "!\n");
956 return 1;
957 }
958
959 static int pbr_vty_map_config_write(struct vty *vty)
960 {
961 struct pbr_map *pbrm;
962
963 pbr_nht_write_table_range(vty);
964 pbr_nht_write_rule_range(vty);
965
966 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
967 struct pbr_map_sequence *pbrms;
968 struct listnode *node;
969
970 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
971 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
972 }
973
974 return 1;
975 }
976
977 static void pbr_map_completer(vector comps, struct cmd_token *token)
978 {
979 struct pbr_map *pbrm;
980
981 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps)
982 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name));
983 }
984
985 static const struct cmd_variable_handler pbr_map_name[] = {
986 {
987 .tokenname = "PBRMAP", .completions = pbr_map_completer,
988 },
989 {
990 .completions = NULL
991 }
992 };
993
994 void pbr_vty_init(void)
995 {
996 cmd_variable_handler_register(pbr_map_name);
997
998 install_node(&interface_node);
999 if_cmd_init();
1000
1001 install_node(&pbr_map_node);
1002
1003 /* debug */
1004 install_node(&debug_node);
1005 install_element(VIEW_NODE, &debug_pbr_cmd);
1006 install_element(CONFIG_NODE, &debug_pbr_cmd);
1007 install_element(VIEW_NODE, &show_debugging_pbr_cmd);
1008
1009 install_default(PBRMAP_NODE);
1010
1011 install_element(CONFIG_NODE, &pbr_map_cmd);
1012 install_element(CONFIG_NODE, &no_pbr_map_cmd);
1013 install_element(CONFIG_NODE, &pbr_set_table_range_cmd);
1014 install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);
1015 install_element(INTERFACE_NODE, &pbr_policy_cmd);
1016 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
1017 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
1018 install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
1019 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
1020 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
1021 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
1022 install_element(PBRMAP_NODE, &no_pbr_map_nexthop_cmd);
1023 install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
1024 install_element(PBRMAP_NODE, &no_pbr_map_vrf_cmd);
1025 install_element(VIEW_NODE, &show_pbr_cmd);
1026 install_element(VIEW_NODE, &show_pbr_map_cmd);
1027 install_element(VIEW_NODE, &show_pbr_interface_cmd);
1028 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
1029 }