]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap_cli.c
*: move CLI node names to cmd_node->name
[mirror_frr.git] / lib / routemap_cli.c
1 /*
2 * Route map northbound CLI implementation.
3 *
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 #include <zebra.h>
24
25 #include "lib/command.h"
26 #include "lib/northbound_cli.h"
27 #include "lib/routemap.h"
28
29 #ifndef VTYSH_EXTRACT_PL
30 #include "lib/routemap_cli_clippy.c"
31 #endif /* VTYSH_EXTRACT_PL */
32
33 #define ROUTE_MAP_CMD_STR \
34 "Create route-map or enter route-map command mode\n" \
35 "Route map tag\n"
36 #define ROUTE_MAP_OP_CMD_STR \
37 "Route map denies set operations\n" \
38 "Route map permits set operations\n"
39 #define ROUTE_MAP_SEQUENCE_CMD_STR \
40 "Sequence to insert to/delete from existing route-map entry\n"
41
42 DEFPY_NOSH(
43 route_map, route_map_cmd,
44 "route-map WORD$name <deny|permit>$action (1-65535)$sequence",
45 ROUTE_MAP_CMD_STR
46 ROUTE_MAP_OP_CMD_STR
47 ROUTE_MAP_SEQUENCE_CMD_STR)
48 {
49 struct route_map_index *rmi;
50 struct route_map *rm;
51 int action_type;
52 char xpath_action[XPATH_MAXLEN + 64];
53 char xpath_index[XPATH_MAXLEN + 32];
54 char xpath[XPATH_MAXLEN];
55 int rv;
56
57 snprintf(xpath, sizeof(xpath),
58 "/frr-route-map:lib/route-map[name='%s']", name);
59 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
60
61 snprintf(xpath_index, sizeof(xpath_index), "%s/entry[sequence='%lu']",
62 xpath, sequence);
63 nb_cli_enqueue_change(vty, xpath_index, NB_OP_CREATE, NULL);
64
65 snprintf(xpath_action, sizeof(xpath_action), "%s/action", xpath_index);
66 nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action);
67
68 rv = nb_cli_apply_changes(vty, NULL);
69 if (rv == CMD_SUCCESS) {
70 VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
71
72 /* Add support for non-migrated route map users. */
73 rm = route_map_get(name);
74 action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY;
75 rmi = route_map_index_get(rm, action_type, sequence);
76 VTY_PUSH_CONTEXT(RMAP_NODE, rmi);
77 }
78
79 return rv;
80 }
81
82 DEFPY(
83 no_route_map_all, no_route_map_all_cmd,
84 "no route-map WORD$name",
85 NO_STR
86 ROUTE_MAP_CMD_STR)
87 {
88 char xpath[XPATH_MAXLEN];
89
90 snprintf(xpath, sizeof(xpath),
91 "/frr-route-map:lib/route-map[name='%s']", name);
92 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
93
94 return nb_cli_apply_changes(vty, NULL);
95 }
96
97 DEFPY(
98 no_route_map, no_route_map_cmd,
99 "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
100 NO_STR
101 ROUTE_MAP_CMD_STR
102 ROUTE_MAP_OP_CMD_STR
103 ROUTE_MAP_SEQUENCE_CMD_STR)
104 {
105 char xpath[XPATH_MAXLEN];
106
107 snprintf(xpath, sizeof(xpath),
108 "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
109 name, sequence);
110 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
111
112 return nb_cli_apply_changes(vty, NULL);
113 }
114
115 void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
116 bool show_defaults)
117 {
118 const struct route_map_rule *rmr;
119 const struct route_map_index *rmi;
120 const char *name = yang_dnode_get_string(dnode, "../name");
121 const char *action = yang_dnode_get_string(dnode, "./action");
122 const char *sequence = yang_dnode_get_string(dnode, "./sequence");
123
124 vty_out(vty, "route-map %s %s %s\n", name, action, sequence);
125
126 rmi = nb_running_get_entry(dnode, NULL, false);
127 if (rmi == NULL) {
128 /*
129 * We can't have outdated rules if route map hasn't
130 * been created yet.
131 */
132 return;
133 }
134
135 #define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue
136
137 /* Print route map `match` for old CLI users. */
138 for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) {
139 /* Skip all matches implemented by northbound. */
140 SKIP_RULE("interface");
141 SKIP_RULE("ip address");
142 SKIP_RULE("ip address prefix-list");
143 SKIP_RULE("ip next-hop");
144 SKIP_RULE("ip next-hop prefix-list");
145 SKIP_RULE("ip next-hop type");
146 SKIP_RULE("ipv6 address");
147 SKIP_RULE("ipv6 address prefix-list");
148 SKIP_RULE("ipv6 next-hop type");
149 SKIP_RULE("metric");
150 SKIP_RULE("tag");
151 /* Zebra specific match conditions. */
152 SKIP_RULE("ip address prefix-len");
153 SKIP_RULE("ipv6 address prefix-len");
154 SKIP_RULE("ip next-hop prefix-len");
155 SKIP_RULE("source-protocol");
156 SKIP_RULE("source-instance");
157
158 vty_out(vty, " match %s %s\n", rmr->cmd->str,
159 rmr->rule_str ? rmr->rule_str : "");
160 }
161
162 /* Print route map `set` for old CLI users. */
163 for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) {
164 /* Skip all sets implemented by northbound. */
165 SKIP_RULE("metric");
166 SKIP_RULE("tag");
167 /* Zebra specific set actions. */
168 SKIP_RULE("src");
169
170 vty_out(vty, " set %s %s\n", rmr->cmd->str,
171 rmr->rule_str ? rmr->rule_str : "");
172 }
173
174 #undef SKIP_RULE
175 }
176
177 void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
178 {
179 vty_out(vty, "!\n");
180 }
181
182 DEFPY(
183 match_interface, match_interface_cmd,
184 "match interface IFNAME",
185 MATCH_STR
186 "Match first hop interface of route\n"
187 INTERFACE_STR)
188 {
189 const char *xpath = "./match-condition[condition='interface']";
190 char xpath_value[XPATH_MAXLEN];
191
192 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
193 snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath);
194 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname);
195
196 return nb_cli_apply_changes(vty, NULL);
197 }
198
199 DEFPY(
200 no_match_interface, no_match_interface_cmd,
201 "no match interface [IFNAME]",
202 NO_STR
203 MATCH_STR
204 "Match first hop interface of route\n"
205 INTERFACE_STR)
206 {
207 const char *xpath = "./match-condition[condition='interface']";
208
209 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
210
211 return nb_cli_apply_changes(vty, NULL);
212 }
213
214 DEFPY(
215 match_ip_address, match_ip_address_cmd,
216 "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
217 MATCH_STR
218 IP_STR
219 "Match address of route\n"
220 "IP access-list number\n"
221 "IP access-list number (expanded range)\n"
222 "IP Access-list name\n")
223 {
224 const char *xpath = "./match-condition[condition='ipv4-address-list']";
225 char xpath_value[XPATH_MAXLEN + 32];
226 int acln = acll ? acll : aclh;
227
228 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
229 if (name) {
230 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
231 xpath);
232 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
233 } else /* if (acll || aclh) */ {
234 if ((acln >= 1 && acln <= 99)
235 || (acln >= 1300 && acln <= 1999)) {
236 snprintf(xpath_value, sizeof(xpath_value),
237 "%s/access-list-num", xpath);
238 } else {
239 /*
240 * if ((acln >= 100 && acln <= 199)
241 * || (acln >= 2000 && acln <= 2699))
242 */
243 snprintf(xpath_value, sizeof(xpath_value),
244 "%s/access-list-num-extended", xpath);
245 }
246 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
247 acll_str ? acll_str : aclh_str);
248 }
249
250 return nb_cli_apply_changes(vty, NULL);
251 }
252
253 DEFPY(
254 no_match_ip_address, no_match_ip_address_cmd,
255 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
256 NO_STR
257 MATCH_STR
258 IP_STR
259 "Match address of route\n"
260 "IP access-list number\n"
261 "IP access-list number (expanded range)\n"
262 "IP Access-list name\n")
263 {
264 const char *xpath = "./match-condition[condition='ipv4-address-list']";
265
266 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
267
268 return nb_cli_apply_changes(vty, NULL);
269 }
270
271 DEFPY(
272 match_ip_address_prefix_list,
273 match_ip_address_prefix_list_cmd,
274 "match ip address prefix-list WORD$name",
275 MATCH_STR
276 IP_STR
277 "Match address of route\n"
278 "Match entries of prefix-lists\n"
279 "IP prefix-list name\n")
280 {
281 const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
282 char xpath_value[XPATH_MAXLEN];
283
284 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
285 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
286 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
287
288 return nb_cli_apply_changes(vty, NULL);
289 }
290
291 DEFPY(
292 no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd,
293 "no match ip address prefix-list [WORD]",
294 NO_STR
295 MATCH_STR
296 IP_STR
297 "Match address of route\n"
298 "Match entries of prefix-lists\n"
299 "IP prefix-list name\n")
300 {
301 const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
302
303 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
304
305 return nb_cli_apply_changes(vty, NULL);
306 }
307
308 DEFPY(
309 match_ip_next_hop, match_ip_next_hop_cmd,
310 "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
311 MATCH_STR
312 IP_STR
313 "Match next-hop address of route\n"
314 "IP access-list number\n"
315 "IP access-list number (expanded range)\n"
316 "IP Access-list name\n")
317 {
318 const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
319 char xpath_value[XPATH_MAXLEN + 32];
320 int acln = acll ? acll : aclh;
321
322 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
323 if (name) {
324 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
325 xpath);
326 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
327 } else /* if (acll || aclh) */ {
328 if ((acln >= 1 && acln <= 99)
329 || (acln >= 1300 && acln <= 1999)) {
330 snprintf(xpath_value, sizeof(xpath_value),
331 "%s/access-list-num", xpath);
332 } else {
333 /*
334 * if ((acln >= 100 && acln <= 199)
335 * || (acln >= 2000 && acln <= 2699))
336 */
337 snprintf(xpath_value, sizeof(xpath_value),
338 "%s/access-list-num-extended", xpath);
339 }
340 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
341 acll_str ? acll_str : aclh_str);
342 }
343
344 return nb_cli_apply_changes(vty, NULL);
345 }
346
347 DEFPY(
348 no_match_ip_next_hop, no_match_ip_next_hop_cmd,
349 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
350 NO_STR
351 MATCH_STR
352 IP_STR
353 "Match address of route\n"
354 "IP access-list number\n"
355 "IP access-list number (expanded range)\n"
356 "IP Access-list name\n")
357 {
358 const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
359
360 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
361
362 return nb_cli_apply_changes(vty, NULL);
363 }
364
365 DEFPY(
366 match_ip_next_hop_prefix_list,
367 match_ip_next_hop_prefix_list_cmd,
368 "match ip next-hop prefix-list WORD$name",
369 MATCH_STR
370 IP_STR
371 "Match next-hop address of route\n"
372 "Match entries of prefix-lists\n"
373 "IP prefix-list name\n")
374 {
375 const char *xpath =
376 "./match-condition[condition='ipv4-next-hop-prefix-list']";
377 char xpath_value[XPATH_MAXLEN];
378
379 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
380 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
381 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
382
383 return nb_cli_apply_changes(vty, NULL);
384 }
385
386 DEFPY(
387 no_match_ip_next_hop_prefix_list,
388 no_match_ip_next_hop_prefix_list_cmd,
389 "no match ip next-hop prefix-list [WORD]",
390 NO_STR
391 MATCH_STR
392 IP_STR
393 "Match next-hop address of route\n"
394 "Match entries of prefix-lists\n"
395 "IP prefix-list name\n")
396 {
397 const char *xpath =
398 "./match-condition[condition='ipv4-next-hop-prefix-list']";
399
400 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
401
402 return nb_cli_apply_changes(vty, NULL);
403 }
404
405 DEFPY(
406 match_ip_next_hop_type, match_ip_next_hop_type_cmd,
407 "match ip next-hop type <blackhole>$type",
408 MATCH_STR
409 IP_STR
410 "Match next-hop address of route\n"
411 "Match entries by type\n"
412 "Blackhole\n")
413 {
414 const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
415 char xpath_value[XPATH_MAXLEN];
416
417 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
418 snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type",
419 xpath);
420 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
421
422 return nb_cli_apply_changes(vty, NULL);
423 }
424
425 DEFPY(
426 no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
427 "no match ip next-hop type [<blackhole>]",
428 NO_STR MATCH_STR IP_STR
429 "Match next-hop address of route\n"
430 "Match entries by type\n"
431 "Blackhole\n")
432 {
433 const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
434
435 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
436
437 return nb_cli_apply_changes(vty, NULL);
438 }
439
440 DEFPY(
441 match_ipv6_address, match_ipv6_address_cmd,
442 "match ipv6 address WORD$name",
443 MATCH_STR
444 IPV6_STR
445 "Match IPv6 address of route\n"
446 "IPv6 access-list name\n")
447 {
448 const char *xpath = "./match-condition[condition='ipv6-address-list']";
449 char xpath_value[XPATH_MAXLEN];
450
451 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
452 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
453 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
454
455 return nb_cli_apply_changes(vty, NULL);
456 }
457
458 DEFPY(
459 no_match_ipv6_address, no_match_ipv6_address_cmd,
460 "no match ipv6 address [WORD]",
461 NO_STR
462 MATCH_STR
463 IPV6_STR
464 "Match IPv6 address of route\n"
465 "IPv6 access-list name\n")
466 {
467 const char *xpath = "./match-condition[condition='ipv6-address-list']";
468
469 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
470
471 return nb_cli_apply_changes(vty, NULL);
472 }
473
474 DEFPY(
475 match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd,
476 "match ipv6 address prefix-list WORD$name",
477 MATCH_STR
478 IPV6_STR
479 "Match address of route\n"
480 "Match entries of prefix-lists\n"
481 "IP prefix-list name\n")
482 {
483 const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
484 char xpath_value[XPATH_MAXLEN];
485
486 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
487 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
488 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
489
490 return nb_cli_apply_changes(vty, NULL);
491 }
492
493 DEFPY(
494 no_match_ipv6_address_prefix_list,
495 no_match_ipv6_address_prefix_list_cmd,
496 "no match ipv6 address prefix-list [WORD]",
497 NO_STR
498 MATCH_STR
499 IPV6_STR
500 "Match address of route\n"
501 "Match entries of prefix-lists\n"
502 "IP prefix-list name\n")
503 {
504 const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
505
506 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
507
508 return nb_cli_apply_changes(vty, NULL);
509 }
510
511 DEFPY(
512 match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
513 "match ipv6 next-hop type <blackhole>$type",
514 MATCH_STR IPV6_STR
515 "Match next-hop address of route\n"
516 "Match entries by type\n"
517 "Blackhole\n")
518 {
519 const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
520 char xpath_value[XPATH_MAXLEN];
521
522 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
523 snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type",
524 xpath);
525 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
526
527 return nb_cli_apply_changes(vty, NULL);
528 }
529
530 DEFPY(
531 no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
532 "no match ipv6 next-hop type [<blackhole>]",
533 NO_STR MATCH_STR IPV6_STR
534 "Match address of route\n"
535 "Match entries by type\n"
536 "Blackhole\n")
537 {
538 const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
539
540 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
541
542 return nb_cli_apply_changes(vty, NULL);
543 }
544
545 DEFPY(
546 match_metric, match_metric_cmd,
547 "match metric (0-4294967295)$metric",
548 MATCH_STR
549 "Match metric of route\n"
550 "Metric value\n")
551 {
552 const char *xpath = "./match-condition[condition='metric']";
553 char xpath_value[XPATH_MAXLEN];
554
555 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
556 snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath);
557 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str);
558
559 return nb_cli_apply_changes(vty, NULL);
560 }
561
562 DEFPY(
563 no_match_metric, no_match_metric_cmd,
564 "no match metric [(0-4294967295)]",
565 NO_STR
566 MATCH_STR
567 "Match metric of route\n"
568 "Metric value\n")
569 {
570 const char *xpath = "./match-condition[condition='metric']";
571
572 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
573
574 return nb_cli_apply_changes(vty, NULL);
575 }
576
577 DEFPY(
578 match_tag, match_tag_cmd,
579 "match tag (1-4294967295)$tag",
580 MATCH_STR
581 "Match tag of route\n"
582 "Tag value\n")
583 {
584 const char *xpath = "./match-condition[condition='tag']";
585 char xpath_value[XPATH_MAXLEN];
586
587 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
588 snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
589 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
590
591 return nb_cli_apply_changes(vty, NULL);
592 }
593
594 DEFPY(
595 no_match_tag, no_match_tag_cmd,
596 "no match tag [(1-4294967295)]",
597 NO_STR
598 MATCH_STR
599 "Match tag of route\n"
600 "Tag value\n")
601 {
602 const char *xpath = "./match-condition[condition='tag']";
603
604 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
605
606 return nb_cli_apply_changes(vty, NULL);
607 }
608
609 void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
610 bool show_defaults)
611 {
612 int condition = yang_dnode_get_enum(dnode, "./condition");
613 struct lyd_node *ln;
614 const char *acl;
615
616 switch (condition) {
617 case 0: /* interface */
618 vty_out(vty, " match interface %s\n",
619 yang_dnode_get_string(dnode, "./interface"));
620 break;
621 case 1: /* ipv4-address-list */
622 case 3: /* ipv4-next-hop-list */
623 acl = NULL;
624 if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL)
625 acl = yang_dnode_get_string(ln, NULL);
626 else if ((ln = yang_dnode_get(dnode, "./access-list-num"))
627 != NULL)
628 acl = yang_dnode_get_string(ln, NULL);
629 else if ((ln = yang_dnode_get(dnode,
630 "./access-list-num-extended"))
631 != NULL)
632 acl = yang_dnode_get_string(ln, NULL);
633
634 assert(acl);
635
636 switch (condition) {
637 case 1:
638 vty_out(vty, " match ip address %s\n", acl);
639 break;
640 case 3:
641 vty_out(vty, " match ip next-hop %s\n", acl);
642 break;
643 }
644 break;
645 case 2: /* ipv4-prefix-list */
646 vty_out(vty, " match ip address prefix-list %s\n",
647 yang_dnode_get_string(dnode, "./list-name"));
648 break;
649 case 4: /* ipv4-next-hop-prefix-list */
650 vty_out(vty, " match ip next-hop prefix-list %s\n",
651 yang_dnode_get_string(dnode, "./list-name"));
652 break;
653 case 5: /* ipv4-next-hop-type */
654 vty_out(vty, " match ip next-hop type %s\n",
655 yang_dnode_get_string(dnode, "./ipv4-next-hop-type"));
656 break;
657 case 6: /* ipv6-address-list */
658 vty_out(vty, " match ipv6 address %s\n",
659 yang_dnode_get_string(dnode, "./list-name"));
660 break;
661 case 7: /* ipv6-prefix-list */
662 vty_out(vty, " match ipv6 address prefix-list %s\n",
663 yang_dnode_get_string(dnode, "./list-name"));
664 break;
665 case 8: /* ipv6-next-hop-type */
666 vty_out(vty, " match ipv6 next-hop type %s\n",
667 yang_dnode_get_string(dnode, "./ipv6-next-hop-type"));
668 break;
669 case 9: /* metric */
670 vty_out(vty, " match metric %s\n",
671 yang_dnode_get_string(dnode, "./metric"));
672 break;
673 case 10: /* tag */
674 vty_out(vty, " match tag %s\n",
675 yang_dnode_get_string(dnode, "./tag"));
676 break;
677 case 100: /* ipv4-prefix-length */
678 vty_out(vty, " match ip address prefix-len %s\n",
679 yang_dnode_get_string(dnode,"./frr-zebra:ipv4-prefix-length"));
680 break;
681 case 101: /* ipv6-prefix-length */
682 vty_out(vty, " match ipv6 address prefix-len %s\n",
683 yang_dnode_get_string(dnode, "./frr-zebra:ipv6-prefix-length"));
684 break;
685 case 102: /* ipv4-next-hop-prefix-length */
686 vty_out(vty, " match ip next-hop prefix-len %s\n",
687 yang_dnode_get_string(dnode, "./frr-zebra:ipv4-prefix-length"));
688 break;
689 case 103: /* source-protocol */
690 vty_out(vty, " match source-protocol %s\n",
691 yang_dnode_get_string(dnode, "./frr-zebra:source-protocol"));
692 break;
693 case 104: /* source-instance */
694 vty_out(vty, " match source-instance %s\n",
695 yang_dnode_get_string(dnode, "./frr-zebra:source-instance"));
696 break;
697 }
698 }
699
700 DEFPY(
701 set_ip_nexthop, set_ip_nexthop_cmd,
702 "set ip next-hop A.B.C.D$addr",
703 SET_STR
704 IP_STR
705 "Next hop address\n"
706 "IP address of next hop\n")
707 {
708 const char *xpath = "./set-action[action='ipv4-next-hop']";
709 char xpath_value[XPATH_MAXLEN];
710
711 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
712 snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath);
713 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
714
715 return nb_cli_apply_changes(vty, NULL);
716 }
717
718 DEFPY(
719 no_set_ip_nexthop, no_set_ip_nexthop_cmd,
720 "no set ip next-hop [A.B.C.D]",
721 NO_STR
722 SET_STR
723 IP_STR
724 "Next hop address\n"
725 "IP address of next hop\n")
726 {
727 const char *xpath = "./set-action[action='ipv4-next-hop']";
728
729 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
730
731 return nb_cli_apply_changes(vty, NULL);
732 }
733
734 DEFPY(
735 set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd,
736 "set ipv6 next-hop local X:X::X:X$addr",
737 SET_STR
738 IPV6_STR
739 "IPv6 next-hop address\n"
740 "IPv6 local address\n"
741 "IPv6 address of next hop\n")
742 {
743 const char *xpath = "./set-action[action='ipv6-next-hop']";
744 char xpath_value[XPATH_MAXLEN];
745
746 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
747 snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath);
748 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
749
750 return nb_cli_apply_changes(vty, NULL);
751 }
752
753 DEFPY(
754 no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd,
755 "no set ipv6 next-hop local [X:X::X:X]",
756 NO_STR
757 SET_STR
758 IPV6_STR
759 "IPv6 next-hop address\n"
760 "IPv6 local address\n"
761 "IPv6 address of next hop\n")
762 {
763 const char *xpath = "./set-action[action='ipv6-next-hop']";
764
765 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
766
767 return nb_cli_apply_changes(vty, NULL);
768 }
769
770 DEFPY(
771 set_metric, set_metric_cmd,
772 "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
773 SET_STR
774 "Metric value for destination routing protocol\n"
775 "Metric value\n"
776 "Assign round trip time\n"
777 "Add round trip time\n"
778 "Subtract round trip time\n"
779 "Add metric\n"
780 "Subtract metric\n")
781 {
782 const char *xpath = "./set-action[action='metric']";
783 char xpath_value[XPATH_MAXLEN];
784 char value[64];
785
786 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
787 if (rtt) {
788 snprintf(xpath_value, sizeof(xpath_value),
789 "%s/use-round-trip-time", xpath);
790 snprintf(value, sizeof(value), "true");
791 } else if (artt) {
792 snprintf(xpath_value, sizeof(xpath_value),
793 "%s/add-round-trip-time", xpath);
794 snprintf(value, sizeof(value), "true");
795 } else if (srtt) {
796 snprintf(xpath_value, sizeof(xpath_value),
797 "%s/subtract-round-trip-time", xpath);
798 snprintf(value, sizeof(value), "true");
799 } else if (ametric) {
800 snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric",
801 xpath);
802 snprintf(value, sizeof(value), "true");
803 } else if (smetric) {
804 snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric",
805 xpath);
806 snprintf(value, sizeof(value), "true");
807 } else {
808 snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath);
809 snprintf(value, sizeof(value), "%lu", metric);
810 }
811 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value);
812
813 return nb_cli_apply_changes(vty, NULL);
814 }
815
816 DEFPY(
817 no_set_metric, no_set_metric_cmd,
818 "no set metric [(0-4294967295)]",
819 NO_STR
820 SET_STR
821 "Metric value for destination routing protocol\n"
822 "Metric value\n")
823 {
824 const char *xpath = "./set-action[action='metric']";
825
826 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
827 return nb_cli_apply_changes(vty, NULL);
828 }
829
830 DEFPY(
831 set_tag, set_tag_cmd,
832 "set tag (1-4294967295)$tag",
833 SET_STR
834 "Tag value for routing protocol\n"
835 "Tag value\n")
836 {
837 const char *xpath = "./set-action[action='tag']";
838 char xpath_value[XPATH_MAXLEN];
839
840 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
841 snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
842 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
843
844 return nb_cli_apply_changes(vty, NULL);
845 }
846
847 DEFPY(
848 no_set_tag, no_set_tag_cmd,
849 "no set tag [(1-4294967295)]",
850 NO_STR
851 SET_STR
852 "Tag value for routing protocol\n"
853 "Tag value\n")
854 {
855 const char *xpath = "./set-action[action='tag']";
856
857 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
858
859 return nb_cli_apply_changes(vty, NULL);
860 }
861
862 void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
863 bool show_defaults)
864 {
865 int action = yang_dnode_get_enum(dnode, "./action");
866
867 switch (action) {
868 case 0: /* ipv4-next-hop */
869 vty_out(vty, " set ip next-hop %s\n",
870 yang_dnode_get_string(dnode, "./ipv4-address"));
871 break;
872 case 1: /* ipv6-next-hop */
873 vty_out(vty, " set ipv6 next-hop local %s\n",
874 yang_dnode_get_string(dnode, "./ipv6-address"));
875 break;
876 case 2: /* metric */
877 if (yang_dnode_get(dnode, "./use-round-trip-time")) {
878 vty_out(vty, " set metric rtt\n");
879 } else if (yang_dnode_get(dnode, "./add-round-trip-time")) {
880 vty_out(vty, " set metric +rtt\n");
881 } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) {
882 vty_out(vty, " set metric -rtt\n");
883 } else if (yang_dnode_get(dnode, "./add-metric")) {
884 vty_out(vty, " set metric +metric\n");
885 } else if (yang_dnode_get(dnode, "./subtract-metric")) {
886 vty_out(vty, " set metric -metric\n");
887 } else {
888 vty_out(vty, " set metric %s\n",
889 yang_dnode_get_string(dnode, "./value"));
890 }
891 break;
892 case 3: /* tag */
893 vty_out(vty, " set tag %s\n",
894 yang_dnode_get_string(dnode, "./tag"));
895 break;
896 case 100: /* source */
897 if (yang_dnode_exists(dnode, "./frr-zebra:source-v4"))
898 vty_out(vty, " set src %s\n",
899 yang_dnode_get_string(dnode, "./frr-zebra:source-v4"));
900 else
901 vty_out(vty, " set src %s\n",
902 yang_dnode_get_string(dnode, "./frr-zebra:source-v6"));
903 break;
904 }
905 }
906
907 DEFPY(
908 rmap_onmatch_next, rmap_onmatch_next_cmd,
909 "on-match next",
910 "Exit policy on matches\n"
911 "Next clause\n")
912 {
913 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next");
914
915 return nb_cli_apply_changes(vty, NULL);
916 }
917
918 DEFPY(
919 no_rmap_onmatch_next,
920 no_rmap_onmatch_next_cmd,
921 "no on-match next",
922 NO_STR
923 "Exit policy on matches\n"
924 "Next clause\n")
925 {
926 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
927
928 return nb_cli_apply_changes(vty, NULL);
929 }
930
931 DEFPY(
932 rmap_onmatch_goto, rmap_onmatch_goto_cmd,
933 "on-match goto (1-65535)$rm_num",
934 "Exit policy on matches\n"
935 "Goto Clause number\n"
936 "Number\n")
937 {
938 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto");
939 nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str);
940
941 return nb_cli_apply_changes(vty, NULL);
942 }
943
944 DEFPY(
945 no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd,
946 "no on-match goto",
947 NO_STR
948 "Exit policy on matches\n"
949 "Goto Clause number\n")
950 {
951 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
952
953 return nb_cli_apply_changes(vty, NULL);
954 }
955
956 /* Cisco/GNU Zebra compatibility aliases */
957 ALIAS(
958 rmap_onmatch_goto, rmap_continue_cmd,
959 "continue (1-65535)$rm_num",
960 "Continue on a different entry within the route-map\n"
961 "Route-map entry sequence number\n")
962
963 ALIAS(
964 no_rmap_onmatch_goto, no_rmap_continue_cmd,
965 "no continue [(1-65535)]",
966 NO_STR
967 "Continue on a different entry within the route-map\n"
968 "Route-map entry sequence number\n")
969
970 void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
971 bool show_defaults)
972 {
973 int exit_policy = yang_dnode_get_enum(dnode, NULL);
974
975 switch (exit_policy) {
976 case 0: /* permit-or-deny */
977 /* NOTHING: default option. */
978 break;
979 case 1: /* next */
980 vty_out(vty, " on-match next\n");
981 break;
982 case 2: /* goto */
983 vty_out(vty, " on-match goto %s\n",
984 yang_dnode_get_string(dnode, "../goto-value"));
985 break;
986 }
987 }
988
989 DEFPY(
990 rmap_call, rmap_call_cmd,
991 "call WORD$name",
992 "Jump to another Route-Map after match+set\n"
993 "Target route-map name\n")
994 {
995 nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name);
996
997 return nb_cli_apply_changes(vty, NULL);
998 }
999
1000 DEFPY(
1001 no_rmap_call, no_rmap_call_cmd,
1002 "no call",
1003 NO_STR
1004 "Jump to another Route-Map after match+set\n")
1005 {
1006 nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL);
1007
1008 return nb_cli_apply_changes(vty, NULL);
1009 }
1010
1011 void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
1012 bool show_defaults)
1013 {
1014 vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
1015 }
1016
1017 DEFPY(
1018 rmap_description, rmap_description_cmd,
1019 "description LINE...",
1020 "Route-map comment\n"
1021 "Comment describing this route-map rule\n")
1022 {
1023 char *desc;
1024 int rv;
1025
1026 desc = argv_concat(argv, argc, 1);
1027 nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
1028 rv = nb_cli_apply_changes(vty, NULL);
1029 XFREE(MTYPE_TMP, desc);
1030
1031 return rv;
1032 }
1033
1034 DEFUN (no_rmap_description,
1035 no_rmap_description_cmd,
1036 "no description",
1037 NO_STR
1038 "Route-map comment\n")
1039 {
1040 nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
1041
1042 return nb_cli_apply_changes(vty, NULL);
1043 }
1044
1045 void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
1046 bool show_defaults)
1047 {
1048 vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
1049 }
1050
1051 static int route_map_config_write(struct vty *vty)
1052 {
1053 struct lyd_node *dnode;
1054 int written = 0;
1055
1056 dnode = yang_dnode_get(running_config->dnode,
1057 "/frr-route-map:lib");
1058 if (dnode) {
1059 nb_cli_show_dnode_cmds(vty, dnode, false);
1060 written = 1;
1061 }
1062
1063 return written;
1064 }
1065
1066 /* Route map node structure. */
1067 static int route_map_config_write(struct vty *vty);
1068 static struct cmd_node rmap_node = {
1069 .name = "routemap",
1070 .node = RMAP_NODE,
1071 .parent_node = CONFIG_NODE,
1072 .prompt = "%s(config-route-map)# ",
1073 .config_write = route_map_config_write,
1074 };
1075
1076 static void rmap_autocomplete(vector comps, struct cmd_token *token)
1077 {
1078 struct route_map *map;
1079
1080 for (map = route_map_master.head; map; map = map->next)
1081 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
1082 }
1083
1084 static const struct cmd_variable_handler rmap_var_handlers[] = {
1085 {.varname = "route_map", .completions = rmap_autocomplete},
1086 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
1087 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
1088 {.completions = NULL}
1089 };
1090
1091 void route_map_cli_init(void)
1092 {
1093 /* Auto complete handler. */
1094 cmd_variable_handler_register(rmap_var_handlers);
1095
1096 /* CLI commands. */
1097 install_node(&rmap_node);
1098 install_default(RMAP_NODE);
1099 install_element(CONFIG_NODE, &route_map_cmd);
1100 install_element(CONFIG_NODE, &no_route_map_cmd);
1101 install_element(CONFIG_NODE, &no_route_map_all_cmd);
1102
1103 /* Install the on-match stuff */
1104 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
1105 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
1106 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
1107 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1108 install_element(RMAP_NODE, &rmap_continue_cmd);
1109 install_element(RMAP_NODE, &no_rmap_continue_cmd);
1110
1111 /* Install the call stuff. */
1112 install_element(RMAP_NODE, &rmap_call_cmd);
1113 install_element(RMAP_NODE, &no_rmap_call_cmd);
1114
1115 /* Install description commands. */
1116 install_element(RMAP_NODE, &rmap_description_cmd);
1117 install_element(RMAP_NODE, &no_rmap_description_cmd);
1118
1119 /* Install 'match' commands. */
1120 install_element(RMAP_NODE, &match_interface_cmd);
1121 install_element(RMAP_NODE, &no_match_interface_cmd);
1122
1123 install_element(RMAP_NODE, &match_ip_address_cmd);
1124 install_element(RMAP_NODE, &no_match_ip_address_cmd);
1125
1126 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
1127 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
1128
1129 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
1130 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
1131
1132 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
1133 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
1134
1135 install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
1136 install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
1137
1138 install_element(RMAP_NODE, &match_ipv6_address_cmd);
1139 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
1140
1141 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
1142 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
1143
1144 install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
1145 install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
1146
1147 install_element(RMAP_NODE, &match_metric_cmd);
1148 install_element(RMAP_NODE, &no_match_metric_cmd);
1149
1150 install_element(RMAP_NODE, &match_tag_cmd);
1151 install_element(RMAP_NODE, &no_match_tag_cmd);
1152
1153 /* Install 'set' commands. */
1154 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
1155 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
1156
1157 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
1158 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
1159
1160 install_element(RMAP_NODE, &set_metric_cmd);
1161 install_element(RMAP_NODE, &no_set_metric_cmd);
1162
1163 install_element(RMAP_NODE, &set_tag_cmd);
1164 install_element(RMAP_NODE, &no_set_tag_cmd);
1165 }