]> git.proxmox.com Git - mirror_frr.git/blame - pbrd/pbr_vty.c
pbrd: fix deletion of match or src of valid pbr-map
[mirror_frr.git] / pbrd / pbr_vty.c
CommitLineData
e5c83d9b
DS
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 "log.h"
29#include "json.h"
30#include "debug.h"
31
32#include "pbrd/pbr_nht.h"
33#include "pbrd/pbr_map.h"
34#include "pbrd/pbr_zebra.h"
35#include "pbrd/pbr_vty.h"
e5c83d9b
DS
36#include "pbrd/pbr_debug.h"
37#ifndef VTYSH_EXTRACT_PL
38#include "pbrd/pbr_vty_clippy.c"
39#endif
40
41DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-1000)",
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
57DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-65535)]",
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);
e5c83d9b
DS
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
b13e5ad6
DS
78 for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, next_node, pbrms)) {
79 if (seqno && pbrms->seqno != seqno)
80 continue;
e5c83d9b 81
b13e5ad6
DS
82 pbr_map_delete(pbrms);
83 }
e5c83d9b
DS
84
85 return CMD_SUCCESS;
86}
87
88DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
89 "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
90 NO_STR
91 "Match the rest of the command\n"
92 "Choose the src ip or ipv6 prefix to use\n"
93 "v4 Prefix\n"
94 "v6 Prefix\n")
95{
96 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b
DS
97
98 if (!no) {
99 if (!pbrms->src)
100 pbrms->src = prefix_new();
101 prefix_copy(pbrms->src, prefix);
102 } else {
103 prefix_free(pbrms->src);
104 pbrms->src = 0;
105 }
106
b13e5ad6 107 pbr_map_check(pbrms);
e5c83d9b
DS
108
109 return CMD_SUCCESS;
110}
111
112DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
113 "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
114 NO_STR
115 "Match the rest of the command\n"
116 "Choose the src ip or ipv6 prefix to use\n"
117 "v4 Prefix\n"
118 "v6 Prefix\n")
119{
120 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
e5c83d9b
DS
121
122 if (!no) {
123 if (!pbrms->dst)
124 pbrms->dst = prefix_new();
125 prefix_copy(pbrms->dst, prefix);
126 } else {
127 prefix_free(pbrms->dst);
b13e5ad6 128 pbrms->dst = NULL;
e5c83d9b
DS
129 }
130
b13e5ad6 131 pbr_map_check(pbrms);
e5c83d9b
DS
132
133 return CMD_SUCCESS;
134}
135
136DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
137 "[no] set nexthop-group NAME$name",
138 NO_STR
139 "Set for the PBR-MAP\n"
140 "nexthop-group to use\n"
141 "The name of the nexthop-group\n")
142{
143 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
144 struct nexthop_group_cmd *nhgc;
e5c83d9b 145
e042a421
DS
146 if (pbrms->nhg) {
147 vty_out(vty,
148 "A `set nexthop XX` command already exists, please remove that first\n");
149 return CMD_WARNING;
150 }
151
e5c83d9b
DS
152 nhgc = nhgc_find(name);
153 if (!nhgc) {
154 vty_out(vty, "Specified nexthop-group %s does not exist\n",
155 name);
156 vty_out(vty, "PBR-MAP will not be applied until it is created\n");
157 }
158
159 if (no) {
160 if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
b13e5ad6 161 pbr_map_delete_nexthop_group(pbrms);
e5c83d9b
DS
162 else {
163 vty_out(vty,
164 "Nexthop Group specified: %s does not exist to remove",
165 name);
166 return CMD_WARNING;
167 }
168 } else {
169 if (pbrms->nhgrp_name) {
170 if (strcmp(name, pbrms->nhgrp_name) != 0) {
171 vty_out(vty,
172 "Please delete current nexthop group before modifying current one");
173 return CMD_WARNING;
174 }
175
176 return CMD_SUCCESS;
177 }
178 pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
b13e5ad6 179 pbr_map_check(pbrms);
e5c83d9b
DS
180 }
181
e5c83d9b
DS
182 return CMD_SUCCESS;
183}
184
185DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
186 "[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
187 NO_STR
188 "Set for the PBR-MAP\n"
189 "Specify one of the nexthops in this map\n"
190 "v4 Address\n"
191 "v6 Address\n"
192 "Interface to use\n"
193 "If the nexthop is in a different vrf tell us\n"
194 "The nexthop-vrf Name\n")
195{
196 struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
197 struct vrf *vrf;
198 struct nexthop nhop;
199 struct nexthop *nh;
e5c83d9b
DS
200
201 if (pbrms->nhgrp_name) {
202 vty_out(vty,
203 "Please unconfigure the nexthop group before adding an individual nexthop");
204 return CMD_WARNING;
205 }
206
207 if (name)
208 vrf = vrf_lookup_by_name(name);
209 else
210 vrf = vrf_lookup_by_id(VRF_DEFAULT);
211
212 if (!vrf) {
213 vty_out(vty, "Specified: %s is non-existent\n", name);
214 return CMD_WARNING;
215 }
216
217 memset(&nhop, 0, sizeof(nhop));
218 nhop.vrf_id = vrf->vrf_id;
219
220 if (addr->sa.sa_family == AF_INET) {
221 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
222 if (intf) {
223 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
224 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
225 if (nhop.ifindex == IFINDEX_INTERNAL) {
226 vty_out(vty,
227 "Specified Intf %s does not exist in vrf: %s\n",
228 intf, vrf->name);
229 return CMD_WARNING;
230 }
231 } else
232 nhop.type = NEXTHOP_TYPE_IPV4;
233 } else {
234 memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
235 if (intf) {
236 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
237 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
238 if (nhop.ifindex == IFINDEX_INTERNAL) {
239 vty_out(vty,
240 "Specified Intf %s does not exist in vrf: %s\n",
241 intf, vrf->name);
242 return CMD_WARNING;
243 }
244 } else
245 nhop.type = NEXTHOP_TYPE_IPV6;
246 }
247
248 if (pbrms->nhg)
249 nh = nexthop_exists(pbrms->nhg, &nhop);
250 else {
251 char buf[100];
252
253 if (no) {
254 vty_out(vty, "No nexthops to delete");
255 return CMD_WARNING;
256 }
257
258 pbrms->nhg = nexthop_group_new();
259 pbrms->internal_nhg_name =
260 XSTRDUP(MTYPE_TMP,
261 pbr_nht_nexthop_make_name(pbrms->parent->name,
262 PBR_MAP_NAMELEN,
263 pbrms->seqno,
264 buf));
265 nh = NULL;
266 }
267
268 if (no) {
b13e5ad6
DS
269 if (nh)
270 pbr_nht_delete_individual_nexthop(pbrms);
e5c83d9b
DS
271 } else if (!nh) {
272
273 if (pbrms->nhg->nexthop) {
274 vty_out(vty,
275 "If you would like more than one nexthop please use nexthop-groups");
276 return CMD_WARNING;
277 }
278
279 /* must be adding new nexthop since !no and !nexthop_exists */
280 nh = nexthop_new();
281
282 memcpy(nh, &nhop, sizeof(nhop));
283 nexthop_add(&pbrms->nhg->nexthop, nh);
284
b13e5ad6
DS
285 pbr_nht_add_individual_nexthop(pbrms);
286 pbr_map_check(pbrms);
e5c83d9b
DS
287 }
288
289 return CMD_SUCCESS;
290}
291
292DEFPY (pbr_table_range,
293 pbr_table_range_cmd,
294 "[no]$no pbr table range (10000-65535)$start (11000-65535)$end",
295 NO_STR
296 "Policy based routing\n"
297 "Policy based routing table\n"
298 "Table range\n"
299 "Initial value of range\n"
300 "Final value of range\n")
301{
302 if (no)
303 pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
304 PBR_NHT_DEFAULT_HIGH_TABLEID);
305 else
306 pbr_nht_set_tableid_range(start, end);
307
308 return CMD_SUCCESS;
309}
310
311DEFPY (pbr_rule_range,
312 pbr_rule_range_cmd,
313 "[no] pbr rule range (300-1300)$start (400-1400)$end",
314 NO_STR
315 "Policy based routing\n"
316 "Policy based routing rule\n"
317 "Rule range\n"
318 "Initial value of range\n"
319 "Final value of range\n")
320{
321 if (no)
322 pbr_nht_set_rule_range(PBR_NHT_DEFAULT_LOW_RULE,
323 PBR_NHT_DEFAULT_HIGH_RULE);
324 else
325 pbr_nht_set_rule_range(start, end);
326
327 return CMD_SUCCESS;
328}
329
330DEFPY (pbr_policy,
331 pbr_policy_cmd,
332 "[no] pbr-policy NAME$mapname",
333 NO_STR
334 "Policy to use\n"
335 "Name of the pbr-map to apply\n")
336{
337 VTY_DECLVAR_CONTEXT(interface, ifp);
338 struct pbr_map *pbrm, *old_pbrm;
339 struct pbr_interface *pbr_ifp = ifp->info;
340
341 pbrm = pbrm_find(mapname);
342
b13e5ad6
DS
343 if (!pbr_ifp) {
344 /*
345 * Some one could have fat fingered the interface
346 * name
347 */
348 pbr_ifp = pbr_if_new(ifp);
349 }
350
e5c83d9b
DS
351 if (no) {
352 if (strcmp(pbr_ifp->mapname, mapname) == 0) {
353 strcpy(pbr_ifp->mapname, "");
354
355 if (pbrm)
356 pbr_map_interface_delete(pbrm, ifp);
357 }
358 } else {
359 if (strcmp(pbr_ifp->mapname, "") == 0) {
360 strcpy(pbr_ifp->mapname, mapname);
361
362 if (pbrm)
363 pbr_map_add_interface(pbrm, ifp);
364 } else {
365 if (!(strcmp(pbr_ifp->mapname, mapname) == 0)) {
366 old_pbrm = pbrm_find(pbr_ifp->mapname);
367 if (old_pbrm)
368 pbr_map_interface_delete(old_pbrm, ifp);
369 strcpy(pbr_ifp->mapname, mapname);
370 if (pbrm)
371 pbr_map_add_interface(pbrm, ifp);
372 }
373 }
374 }
375
376 return CMD_SUCCESS;
377}
378
379DEFPY (show_pbr,
380 show_pbr_cmd,
381 "show pbr [json$json]",
382 SHOW_STR
383 "Policy Based Routing\n"
384 JSON_STR)
385{
386 pbr_nht_write_table_range(vty);
387 pbr_nht_write_rule_range(vty);
388
389 return CMD_SUCCESS;
390}
391
392DEFPY (show_pbr_map,
393 show_pbr_map_cmd,
394 "show pbr map [NAME$name] [detail$detail] [json$json]",
395 SHOW_STR
396 "Policy Based Routing\n"
397 "PBR Map\n"
398 "PBR Map Name\n"
399 "Detailed information\n"
400 JSON_STR)
401{
402 struct pbr_map_sequence *pbrms;
403 struct pbr_map *pbrm;
404 struct listnode *node;
405 char buf[PREFIX_STRLEN];
406 char rbuf[64];
407
408 RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
409 if (name && strcmp(name, pbrm->name) != 0)
410 continue;
411
412 vty_out(vty, " pbr-map %s valid: %d\n", pbrm->name,
413 pbrm->valid);
414
415 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
416 if (pbrms->reason)
417 pbr_map_reason_string(pbrms->reason, rbuf,
418 sizeof(rbuf));
419 vty_out(vty,
420 " Seq: %u rule: %u Installed: %d(%u) Reason: %s\n",
421 pbrms->seqno, pbrms->ruleno, pbrms->installed,
422 pbrms->unique, pbrms->reason ? rbuf : "Valid");
423
424 if (pbrms->src)
425 vty_out(vty, "\tSRC Match: %s\n",
426 prefix2str(pbrms->src, buf,
427 sizeof(buf)));
428 if (pbrms->dst)
429 vty_out(vty, "\tDST Match: %s\n",
430 prefix2str(pbrms->dst, buf,
431 sizeof(buf)));
432
433 if (pbrms->nhgrp_name) {
434 vty_out(vty,
435 "\tNexthop-Group: %s(%u) Installed: %u(%d)\n",
436 pbrms->nhgrp_name,
437 pbr_nht_get_table(pbrms->nhgrp_name),
438 pbrms->nhs_installed,
439 pbr_nht_get_installed(
440 pbrms->nhgrp_name));
441 } else if (pbrms->nhg) {
442 vty_out(vty, " ");
443 nexthop_group_write_nexthop(
444 vty, pbrms->nhg->nexthop);
445 vty_out(vty,
446 "\tInstalled: %u(%d) Tableid: %d\n",
447 pbrms->nhs_installed,
448 pbr_nht_get_installed(
449 pbrms->internal_nhg_name),
450 pbr_nht_get_table(
451 pbrms->internal_nhg_name));
452 } else {
453 vty_out(vty,
454 "\tNexthop-Group: Unknown Installed: 0(0)\n");
455 }
456 }
457 }
458 return CMD_SUCCESS;
459}
460
461DEFPY(show_pbr_nexthop_group,
462 show_pbr_nexthop_group_cmd,
463 "show pbr nexthop-groups [WORD$word]",
464 SHOW_STR
465 "Policy Based Routing\n"
466 "Nexthop Groups\n"
467 "Optional Name of the nexthop group\n")
468{
469 pbr_nht_show_nexthop_group(vty, word);
470
471 return CMD_SUCCESS;
472}
473
474DEFPY (show_pbr_interface,
475 show_pbr_interface_cmd,
476 "show pbr interface [NAME$name] [json$json]",
477 SHOW_STR
478 "Policy Based Routing\n"
479 "PBR Interface\n"
480 "PBR Interface Name\n"
481 JSON_STR)
482{
d3765386 483 struct interface *ifp;
e5c83d9b
DS
484 struct vrf *vrf;
485 struct pbr_interface *pbr_ifp;
486
487 RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
488 FOR_ALL_INTERFACES(vrf, ifp) {
489 struct pbr_map *pbrm;
490
491 if (name && strcmp(ifp->name, name) != 0)
492 continue;
493
494 pbr_ifp = ifp->info;
495
496 if (strcmp(pbr_ifp->mapname, "") == 0)
497 continue;
498
499 pbrm = pbrm_find(pbr_ifp->mapname);
500 vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
501 ifp->ifindex, pbr_ifp->mapname);
502 if (!pbrm)
503 vty_out(vty, " (map doesn't exist)");
504 vty_out(vty, "\n");
505 }
506 }
507
508 return CMD_SUCCESS;
509}
510
511static struct cmd_node interface_node = {
512 INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
513};
514
515static int pbr_interface_config_write(struct vty *vty)
516{
517 struct interface *ifp;
518 struct vrf *vrf;
519
520 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
521 FOR_ALL_INTERFACES (vrf, ifp) {
522 if (vrf->vrf_id == VRF_DEFAULT)
523 vty_frame(vty, "interface %s\n", ifp->name);
524 else
525 vty_frame(vty, "interface %s vrf %s\n",
526 ifp->name, vrf->name);
527
528 pbr_map_write_interfaces(vty, ifp);
529
530 vty_endframe(vty, "!\n");
531 }
532 }
533
534 return 1;
535}
536
537/* PBR map node structure. */
538static struct cmd_node pbr_map_node = {PBRMAP_NODE, "%s(config-pbr-map)# ", 1};
539
540static int pbr_vty_map_config_write_sequence(struct vty *vty,
541 struct pbr_map *pbrm,
542 struct pbr_map_sequence *pbrms)
543{
544 char buff[PREFIX_STRLEN];
545
57cdafc4 546 vty_frame(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
e5c83d9b
DS
547
548 if (pbrms->src)
549 vty_out(vty, " match src-ip %s\n",
d3765386 550 prefix2str(pbrms->src, buff, sizeof(buff)));
e5c83d9b
DS
551
552 if (pbrms->dst)
553 vty_out(vty, " match dst-ip %s\n",
d3765386 554 prefix2str(pbrms->dst, buff, sizeof(buff)));
e5c83d9b
DS
555
556 if (pbrms->nhgrp_name)
557 vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
558
559 if (pbrms->nhg) {
57cdafc4 560 vty_out(vty, " set ");
e5c83d9b
DS
561 nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
562 }
563
57cdafc4 564 vty_endframe(vty, "!\n");
e5c83d9b
DS
565 return 1;
566}
567
568static int pbr_vty_map_config_write(struct vty *vty)
569{
570 struct pbr_map *pbrm;
571
572 pbr_nht_write_table_range(vty);
573 pbr_nht_write_rule_range(vty);
574
575 RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
576 struct pbr_map_sequence *pbrms;
577 struct listnode *node;
578
d3765386 579 for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
e5c83d9b 580 pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
e5c83d9b
DS
581 }
582
583 return 1;
584}
585
586void pbr_vty_init(void)
587{
588 install_node(&interface_node,
589 pbr_interface_config_write);
590 if_cmd_init();
591
592 install_node(&pbr_map_node,
593 pbr_vty_map_config_write);
594
595 install_default(PBRMAP_NODE);
596
597 install_element(CONFIG_NODE, &pbr_map_cmd);
598 install_element(CONFIG_NODE, &no_pbr_map_cmd);
599 install_element(INTERFACE_NODE, &pbr_policy_cmd);
600 install_element(CONFIG_NODE, &pbr_table_range_cmd);
601 install_element(CONFIG_NODE, &pbr_rule_range_cmd);
602 install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
603 install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
604 install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
605 install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
606 install_element(VIEW_NODE, &show_pbr_cmd);
607 install_element(VIEW_NODE, &show_pbr_map_cmd);
608 install_element(VIEW_NODE, &show_pbr_interface_cmd);
609 install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
610
611 pbr_debug_init_vty();
e5c83d9b 612}