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