2 * Route map northbound CLI implementation.
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
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.
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.
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
25 #include "lib/command.h"
26 #include "lib/northbound_cli.h"
27 #include "lib/routemap.h"
29 #ifndef VTYSH_EXTRACT_PL
30 #include "lib/routemap_cli_clippy.c"
31 #endif /* VTYSH_EXTRACT_PL */
33 #define ROUTE_MAP_CMD_STR \
34 "Create route-map or enter route-map command mode\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"
43 route_map
, route_map_cmd
,
44 "route-map WORD$name <deny|permit>$action (1-65535)$sequence",
47 ROUTE_MAP_SEQUENCE_CMD_STR
)
49 struct route_map_index
*rmi
;
52 char xpath_action
[XPATH_MAXLEN
+ 64];
53 char xpath_index
[XPATH_MAXLEN
+ 32];
54 char xpath
[XPATH_MAXLEN
];
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
);
61 snprintf(xpath_index
, sizeof(xpath_index
), "%s/entry[sequence='%lu']",
63 nb_cli_enqueue_change(vty
, xpath_index
, NB_OP_CREATE
, NULL
);
65 snprintf(xpath_action
, sizeof(xpath_action
), "%s/action", xpath_index
);
66 nb_cli_enqueue_change(vty
, xpath_action
, NB_OP_MODIFY
, action
);
68 rv
= nb_cli_apply_changes(vty
, NULL
);
69 if (rv
== CMD_SUCCESS
) {
70 VTY_PUSH_XPATH(RMAP_NODE
, xpath_index
);
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
);
84 no_route_map_all
, no_route_map_all_cmd
,
85 "no route-map WORD$name",
89 char xpath
[XPATH_MAXLEN
];
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
);
95 return nb_cli_apply_changes(vty
, NULL
);
99 no_route_map
, no_route_map_cmd
,
100 "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
104 ROUTE_MAP_SEQUENCE_CMD_STR
)
106 char xpath
[XPATH_MAXLEN
];
108 snprintf(xpath
, sizeof(xpath
),
109 "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
111 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
113 return nb_cli_apply_changes(vty
, NULL
);
116 void route_map_instance_show(struct vty
*vty
, struct lyd_node
*dnode
,
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");
125 vty_out(vty
, "route-map %s %s %s\n", name
, action
, sequence
);
127 rmi
= nb_running_get_entry(dnode
, NULL
, false);
130 * We can't have outdated rules if route map hasn't
136 #define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue
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");
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");
159 vty_out(vty
, " match %s %s\n", rmr
->cmd
->str
,
160 rmr
->rule_str
? rmr
->rule_str
: "");
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. */
168 /* Zebra specific set actions. */
171 vty_out(vty
, " set %s %s\n", rmr
->cmd
->str
,
172 rmr
->rule_str
? rmr
->rule_str
: "");
178 void route_map_instance_show_end(struct vty
*vty
, struct lyd_node
*dnode
)
184 match_interface
, match_interface_cmd
,
185 "match interface IFNAME",
187 "Match first hop interface of route\n"
190 const char *xpath
= "./match-condition[condition='interface']";
191 char xpath_value
[XPATH_MAXLEN
];
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
);
197 return nb_cli_apply_changes(vty
, NULL
);
201 no_match_interface
, no_match_interface_cmd
,
202 "no match interface [IFNAME]",
205 "Match first hop interface of route\n"
208 const char *xpath
= "./match-condition[condition='interface']";
210 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
212 return nb_cli_apply_changes(vty
, NULL
);
216 match_ip_address
, match_ip_address_cmd
,
217 "match ip address <(1-199)|(1300-2699)|WORD>$name",
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")
225 const char *xpath
= "./match-condition[condition='ipv4-address-list']";
226 char xpath_value
[XPATH_MAXLEN
+ 32];
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
);
232 return nb_cli_apply_changes(vty
, NULL
);
236 no_match_ip_address
, no_match_ip_address_cmd
,
237 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
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")
246 const char *xpath
= "./match-condition[condition='ipv4-address-list']";
248 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
250 return nb_cli_apply_changes(vty
, NULL
);
254 match_ip_address_prefix_list
,
255 match_ip_address_prefix_list_cmd
,
256 "match ip address prefix-list WORD$name",
259 "Match address of route\n"
260 "Match entries of prefix-lists\n"
261 "IP prefix-list name\n")
263 const char *xpath
= "./match-condition[condition='ipv4-prefix-list']";
264 char xpath_value
[XPATH_MAXLEN
];
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
);
270 return nb_cli_apply_changes(vty
, NULL
);
274 no_match_ip_address_prefix_list
, no_match_ip_address_prefix_list_cmd
,
275 "no match ip address prefix-list [WORD]",
279 "Match address of route\n"
280 "Match entries of prefix-lists\n"
281 "IP prefix-list name\n")
283 const char *xpath
= "./match-condition[condition='ipv4-prefix-list']";
285 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
287 return nb_cli_apply_changes(vty
, NULL
);
291 match_ip_next_hop
, match_ip_next_hop_cmd
,
292 "match ip next-hop <(1-199)|(1300-2699)|WORD>$name",
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")
300 const char *xpath
= "./match-condition[condition='ipv4-next-hop-list']";
301 char xpath_value
[XPATH_MAXLEN
+ 32];
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
);
307 return nb_cli_apply_changes(vty
, NULL
);
311 no_match_ip_next_hop
, no_match_ip_next_hop_cmd
,
312 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
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")
321 const char *xpath
= "./match-condition[condition='ipv4-next-hop-list']";
323 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
325 return nb_cli_apply_changes(vty
, NULL
);
329 match_ip_next_hop_prefix_list
,
330 match_ip_next_hop_prefix_list_cmd
,
331 "match ip next-hop prefix-list WORD$name",
334 "Match next-hop address of route\n"
335 "Match entries of prefix-lists\n"
336 "IP prefix-list name\n")
339 "./match-condition[condition='ipv4-next-hop-prefix-list']";
340 char xpath_value
[XPATH_MAXLEN
];
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
);
346 return nb_cli_apply_changes(vty
, NULL
);
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]",
356 "Match next-hop address of route\n"
357 "Match entries of prefix-lists\n"
358 "IP prefix-list name\n")
361 "./match-condition[condition='ipv4-next-hop-prefix-list']";
363 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
365 return nb_cli_apply_changes(vty
, NULL
);
369 match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
370 "match ip next-hop type <blackhole>$type",
373 "Match next-hop address of route\n"
374 "Match entries by type\n"
377 const char *xpath
= "./match-condition[condition='ipv4-next-hop-type']";
378 char xpath_value
[XPATH_MAXLEN
];
380 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
381 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv4-next-hop-type",
383 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, type
);
385 return nb_cli_apply_changes(vty
, NULL
);
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"
396 const char *xpath
= "./match-condition[condition='ipv4-next-hop-type']";
398 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
400 return nb_cli_apply_changes(vty
, NULL
);
404 match_ipv6_address
, match_ipv6_address_cmd
,
405 "match ipv6 address WORD$name",
408 "Match IPv6 address of route\n"
409 "IPv6 access-list name\n")
411 const char *xpath
= "./match-condition[condition='ipv6-address-list']";
412 char xpath_value
[XPATH_MAXLEN
];
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
);
418 return nb_cli_apply_changes(vty
, NULL
);
422 no_match_ipv6_address
, no_match_ipv6_address_cmd
,
423 "no match ipv6 address [WORD]",
427 "Match IPv6 address of route\n"
428 "IPv6 access-list name\n")
430 const char *xpath
= "./match-condition[condition='ipv6-address-list']";
432 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
434 return nb_cli_apply_changes(vty
, NULL
);
438 match_ipv6_address_prefix_list
, match_ipv6_address_prefix_list_cmd
,
439 "match ipv6 address prefix-list WORD$name",
442 "Match address of route\n"
443 "Match entries of prefix-lists\n"
444 "IP prefix-list name\n")
446 const char *xpath
= "./match-condition[condition='ipv6-prefix-list']";
447 char xpath_value
[XPATH_MAXLEN
];
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
);
453 return nb_cli_apply_changes(vty
, NULL
);
457 no_match_ipv6_address_prefix_list
,
458 no_match_ipv6_address_prefix_list_cmd
,
459 "no match ipv6 address prefix-list [WORD]",
463 "Match address of route\n"
464 "Match entries of prefix-lists\n"
465 "IP prefix-list name\n")
467 const char *xpath
= "./match-condition[condition='ipv6-prefix-list']";
469 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
471 return nb_cli_apply_changes(vty
, NULL
);
475 match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
476 "match ipv6 next-hop type <blackhole>$type",
478 "Match next-hop address of route\n"
479 "Match entries by type\n"
482 const char *xpath
= "./match-condition[condition='ipv6-next-hop-type']";
483 char xpath_value
[XPATH_MAXLEN
];
485 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
486 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv6-next-hop-type",
488 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, type
);
490 return nb_cli_apply_changes(vty
, NULL
);
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"
501 const char *xpath
= "./match-condition[condition='ipv6-next-hop-type']";
503 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
505 return nb_cli_apply_changes(vty
, NULL
);
509 match_metric
, match_metric_cmd
,
510 "match metric (0-4294967295)$metric",
512 "Match metric of route\n"
515 const char *xpath
= "./match-condition[condition='metric']";
516 char xpath_value
[XPATH_MAXLEN
];
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
);
522 return nb_cli_apply_changes(vty
, NULL
);
526 no_match_metric
, no_match_metric_cmd
,
527 "no match metric [(0-4294967295)]",
530 "Match metric of route\n"
533 const char *xpath
= "./match-condition[condition='metric']";
535 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
537 return nb_cli_apply_changes(vty
, NULL
);
541 match_tag
, match_tag_cmd
,
542 "match tag (1-4294967295)$tag",
544 "Match tag of route\n"
547 const char *xpath
= "./match-condition[condition='tag']";
548 char xpath_value
[XPATH_MAXLEN
];
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
);
554 return nb_cli_apply_changes(vty
, NULL
);
558 no_match_tag
, no_match_tag_cmd
,
559 "no match tag [(1-4294967295)]",
562 "Match tag of route\n"
565 const char *xpath
= "./match-condition[condition='tag']";
567 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
569 return nb_cli_apply_changes(vty
, NULL
);
572 void route_map_condition_show(struct vty
*vty
, struct lyd_node
*dnode
,
575 int condition
= yang_dnode_get_enum(dnode
, "./condition");
578 case 0: /* interface */
579 vty_out(vty
, " match interface %s\n",
580 yang_dnode_get_string(dnode
, "./interface"));
582 case 1: /* ipv4-address-list */
583 case 3: /* ipv4-next-hop-list */
586 vty_out(vty
, " match ip address %s\n",
587 yang_dnode_get_string(dnode
, "./list-name"));
590 vty_out(vty
, " match ip next-hop %s\n",
591 yang_dnode_get_string(dnode
, "./list-name"));
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"));
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"));
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"));
607 case 6: /* ipv6-address-list */
608 vty_out(vty
, " match ipv6 address %s\n",
609 yang_dnode_get_string(dnode
, "./list-name"));
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"));
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"));
620 vty_out(vty
, " match metric %s\n",
621 yang_dnode_get_string(dnode
, "./metric"));
624 vty_out(vty
, " match tag %s\n",
625 yang_dnode_get_string(dnode
, "./tag"));
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"));
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"));
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"));
639 case 103: /* source-protocol */
640 vty_out(vty
, " match source-protocol %s\n",
641 yang_dnode_get_string(dnode
, "./frr-zebra:source-protocol"));
643 case 104: /* source-instance */
644 vty_out(vty
, " match source-instance %s\n",
645 yang_dnode_get_string(dnode
, "./frr-zebra:source-instance"));
651 set_ip_nexthop
, set_ip_nexthop_cmd
,
652 "set ip next-hop A.B.C.D$addr",
656 "IP address of next hop\n")
658 const char *xpath
= "./set-action[action='ipv4-next-hop']";
659 char xpath_value
[XPATH_MAXLEN
];
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
);
665 return nb_cli_apply_changes(vty
, NULL
);
669 no_set_ip_nexthop
, no_set_ip_nexthop_cmd
,
670 "no set ip next-hop [A.B.C.D]",
675 "IP address of next hop\n")
677 const char *xpath
= "./set-action[action='ipv4-next-hop']";
679 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
681 return nb_cli_apply_changes(vty
, NULL
);
685 set_ipv6_nexthop_local
, set_ipv6_nexthop_local_cmd
,
686 "set ipv6 next-hop local X:X::X:X$addr",
689 "IPv6 next-hop address\n"
690 "IPv6 local address\n"
691 "IPv6 address of next hop\n")
693 const char *xpath
= "./set-action[action='ipv6-next-hop']";
694 char xpath_value
[XPATH_MAXLEN
];
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
);
700 return nb_cli_apply_changes(vty
, NULL
);
704 no_set_ipv6_nexthop_local
, no_set_ipv6_nexthop_local_cmd
,
705 "no set ipv6 next-hop local [X:X::X:X]",
709 "IPv6 next-hop address\n"
710 "IPv6 local address\n"
711 "IPv6 address of next hop\n")
713 const char *xpath
= "./set-action[action='ipv6-next-hop']";
715 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
717 return nb_cli_apply_changes(vty
, NULL
);
721 set_metric
, set_metric_cmd
,
722 "set metric <(-4294967295-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt>",
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")
730 const char *xpath
= "./set-action[action='metric']";
731 char xpath_value
[XPATH_MAXLEN
];
734 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
736 snprintf(xpath_value
, sizeof(xpath_value
),
737 "%s/use-round-trip-time", xpath
);
738 snprintf(value
, sizeof(value
), "true");
740 snprintf(xpath_value
, sizeof(xpath_value
),
741 "%s/add-round-trip-time", xpath
);
742 snprintf(value
, sizeof(value
), "true");
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",
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",
754 snprintf(value
, sizeof(value
), "%s", ++metric_str
);
756 snprintf(xpath_value
, sizeof(xpath_value
), "%s/value", xpath
);
757 snprintf(value
, sizeof(value
), "%s", metric_str
);
759 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, value
);
761 return nb_cli_apply_changes(vty
, NULL
);
765 no_set_metric
, no_set_metric_cmd
,
766 "no set metric [(0-4294967295)]",
769 "Metric value for destination routing protocol\n"
772 const char *xpath
= "./set-action[action='metric']";
774 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
775 return nb_cli_apply_changes(vty
, NULL
);
779 set_tag
, set_tag_cmd
,
780 "set tag (1-4294967295)$tag",
782 "Tag value for routing protocol\n"
785 const char *xpath
= "./set-action[action='tag']";
786 char xpath_value
[XPATH_MAXLEN
];
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
);
792 return nb_cli_apply_changes(vty
, NULL
);
796 no_set_tag
, no_set_tag_cmd
,
797 "no set tag [(1-4294967295)]",
800 "Tag value for routing protocol\n"
803 const char *xpath
= "./set-action[action='tag']";
805 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
807 return nb_cli_apply_changes(vty
, NULL
);
810 void route_map_action_show(struct vty
*vty
, struct lyd_node
*dnode
,
813 int action
= yang_dnode_get_enum(dnode
, "./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"));
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"));
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"));
839 vty_out(vty
, " set metric %s\n",
840 yang_dnode_get_string(dnode
, "./value"));
844 vty_out(vty
, " set tag %s\n",
845 yang_dnode_get_string(dnode
, "./tag"));
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"));
852 vty_out(vty
, " set src %s\n",
853 yang_dnode_get_string(dnode
, "./frr-zebra:source-v6"));
859 rmap_onmatch_next
, rmap_onmatch_next_cmd
,
861 "Exit policy on matches\n"
864 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_MODIFY
, "next");
866 return nb_cli_apply_changes(vty
, NULL
);
870 no_rmap_onmatch_next
,
871 no_rmap_onmatch_next_cmd
,
874 "Exit policy on matches\n"
877 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_DESTROY
, NULL
);
879 return nb_cli_apply_changes(vty
, NULL
);
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"
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
);
892 return nb_cli_apply_changes(vty
, NULL
);
896 no_rmap_onmatch_goto
, no_rmap_onmatch_goto_cmd
,
899 "Exit policy on matches\n"
900 "Goto Clause number\n")
902 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_DESTROY
, NULL
);
904 return nb_cli_apply_changes(vty
, NULL
);
907 /* Cisco/GNU Zebra compatibility aliases */
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")
915 no_rmap_onmatch_goto
, no_rmap_continue_cmd
,
916 "no continue [(1-65535)]",
918 "Continue on a different entry within the route-map\n"
919 "Route-map entry sequence number\n")
921 void route_map_exit_policy_show(struct vty
*vty
, struct lyd_node
*dnode
,
924 int exit_policy
= yang_dnode_get_enum(dnode
, NULL
);
926 switch (exit_policy
) {
927 case 0: /* permit-or-deny */
928 /* NOTHING: default option. */
931 vty_out(vty
, " on-match next\n");
934 vty_out(vty
, " on-match goto %s\n",
935 yang_dnode_get_string(dnode
, "../goto-value"));
941 rmap_call
, rmap_call_cmd
,
943 "Jump to another Route-Map after match+set\n"
944 "Target route-map name\n")
946 nb_cli_enqueue_change(vty
, "./call", NB_OP_MODIFY
, name
);
948 return nb_cli_apply_changes(vty
, NULL
);
952 no_rmap_call
, no_rmap_call_cmd
,
955 "Jump to another Route-Map after match+set\n"
956 "Target route-map name\n")
958 nb_cli_enqueue_change(vty
, "./call", NB_OP_DESTROY
, NULL
);
960 return nb_cli_apply_changes(vty
, NULL
);
963 void route_map_call_show(struct vty
*vty
, struct lyd_node
*dnode
,
966 vty_out(vty
, " call %s\n", yang_dnode_get_string(dnode
, NULL
));
970 rmap_description
, rmap_description_cmd
,
971 "description LINE...",
972 "Route-map comment\n"
973 "Comment describing this route-map rule\n")
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
);
986 DEFUN_YANG (no_rmap_description
,
987 no_rmap_description_cmd
,
990 "Route-map comment\n")
992 nb_cli_enqueue_change(vty
, "./description", NB_OP_DESTROY
, NULL
);
994 return nb_cli_apply_changes(vty
, NULL
);
997 void route_map_description_show(struct vty
*vty
, struct lyd_node
*dnode
,
1000 vty_out(vty
, " description %s\n", yang_dnode_get_string(dnode
, NULL
));
1003 static int route_map_config_write(struct vty
*vty
)
1005 struct lyd_node
*dnode
;
1008 dnode
= yang_dnode_get(running_config
->dnode
,
1009 "/frr-route-map:lib");
1011 nb_cli_show_dnode_cmds(vty
, dnode
, false);
1018 /* Route map node structure. */
1019 static int route_map_config_write(struct vty
*vty
);
1020 static struct cmd_node rmap_node
= {
1023 .parent_node
= CONFIG_NODE
,
1024 .prompt
= "%s(config-route-map)# ",
1025 .config_write
= route_map_config_write
,
1028 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
1030 struct route_map
*map
;
1032 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1033 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
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
}
1043 void route_map_cli_init(void)
1045 /* Auto complete handler. */
1046 cmd_variable_handler_register(rmap_var_handlers
);
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
);
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
);
1063 /* Install the call stuff. */
1064 install_element(RMAP_NODE
, &rmap_call_cmd
);
1065 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
1067 /* Install description commands. */
1068 install_element(RMAP_NODE
, &rmap_description_cmd
);
1069 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
1071 /* Install 'match' commands. */
1072 install_element(RMAP_NODE
, &match_interface_cmd
);
1073 install_element(RMAP_NODE
, &no_match_interface_cmd
);
1075 install_element(RMAP_NODE
, &match_ip_address_cmd
);
1076 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
1078 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
1079 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
1081 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
1082 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
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
);
1087 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
1088 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
1090 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
1091 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
1093 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
1094 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
1096 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
1097 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
1099 install_element(RMAP_NODE
, &match_metric_cmd
);
1100 install_element(RMAP_NODE
, &no_match_metric_cmd
);
1102 install_element(RMAP_NODE
, &match_tag_cmd
);
1103 install_element(RMAP_NODE
, &no_match_tag_cmd
);
1105 /* Install 'set' commands. */
1106 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
1107 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
1109 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
1110 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
1112 install_element(RMAP_NODE
, &set_metric_cmd
);
1113 install_element(RMAP_NODE
, &no_set_metric_cmd
);
1115 install_element(RMAP_NODE
, &set_tag_cmd
);
1116 install_element(RMAP_NODE
, &no_set_tag_cmd
);