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 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
);
83 no_route_map_all
, no_route_map_all_cmd
,
84 "no route-map WORD$name",
88 char xpath
[XPATH_MAXLEN
];
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
);
94 return nb_cli_apply_changes(vty
, NULL
);
98 no_route_map
, no_route_map_cmd
,
99 "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
103 ROUTE_MAP_SEQUENCE_CMD_STR
)
105 char xpath
[XPATH_MAXLEN
];
107 snprintf(xpath
, sizeof(xpath
),
108 "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
110 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
112 return nb_cli_apply_changes(vty
, NULL
);
115 void route_map_instance_show(struct vty
*vty
, struct lyd_node
*dnode
,
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");
124 vty_out(vty
, "route-map %s %s %s\n", name
, action
, sequence
);
126 rmi
= nb_running_get_entry(dnode
, NULL
, false);
129 * We can't have outdated rules if route map hasn't
135 #define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue
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");
152 vty_out(vty
, " match %s %s\n", rmr
->cmd
->str
,
153 rmr
->rule_str
? rmr
->rule_str
: "");
156 /* Print route map `set` for old CLI users. */
157 for (rmr
= rmi
->set_list
.head
; rmr
; rmr
= rmr
->next
) {
158 /* Skip all sets implemented by northbound. */
162 vty_out(vty
, " set %s %s\n", rmr
->cmd
->str
,
163 rmr
->rule_str
? rmr
->rule_str
: "");
169 void route_map_instance_show_end(struct vty
*vty
, struct lyd_node
*dnode
)
175 match_interface
, match_interface_cmd
,
176 "match interface IFNAME",
178 "Match first hop interface of route\n"
181 const char *xpath
= "./match-condition[condition='interface']";
182 char xpath_value
[XPATH_MAXLEN
];
184 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
185 snprintf(xpath_value
, sizeof(xpath_value
), "%s/interface", xpath
);
186 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, ifname
);
188 return nb_cli_apply_changes(vty
, NULL
);
192 no_match_interface
, no_match_interface_cmd
,
193 "no match interface [IFNAME]",
196 "Match first hop interface of route\n"
199 const char *xpath
= "./match-condition[condition='interface']";
201 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
203 return nb_cli_apply_changes(vty
, NULL
);
207 match_ip_address
, match_ip_address_cmd
,
208 "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
211 "Match address of route\n"
212 "IP access-list number\n"
213 "IP access-list number (expanded range)\n"
214 "IP Access-list name\n")
216 const char *xpath
= "./match-condition[condition='ipv4-address-list']";
217 char xpath_value
[XPATH_MAXLEN
+ 32];
218 int acln
= acll
? acll
: aclh
;
220 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
222 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name",
224 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
225 } else /* if (acll || aclh) */ {
226 if ((acln
>= 1 && acln
<= 99)
227 || (acln
>= 1300 && acln
<= 1999)) {
228 snprintf(xpath_value
, sizeof(xpath_value
),
229 "%s/access-list-num", xpath
);
232 * if ((acln >= 100 && acln <= 199)
233 * || (acln >= 2000 && acln <= 2699))
235 snprintf(xpath_value
, sizeof(xpath_value
),
236 "%s/access-list-num-extended", xpath
);
238 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
239 acll_str
? acll_str
: aclh_str
);
242 return nb_cli_apply_changes(vty
, NULL
);
246 no_match_ip_address
, no_match_ip_address_cmd
,
247 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
251 "Match address of route\n"
252 "IP access-list number\n"
253 "IP access-list number (expanded range)\n"
254 "IP Access-list name\n")
256 const char *xpath
= "./match-condition[condition='ipv4-address-list']";
258 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
260 return nb_cli_apply_changes(vty
, NULL
);
264 match_ip_address_prefix_list
,
265 match_ip_address_prefix_list_cmd
,
266 "match ip address prefix-list WORD$name",
269 "Match address of route\n"
270 "Match entries of prefix-lists\n"
271 "IP prefix-list name\n")
273 const char *xpath
= "./match-condition[condition='ipv4-prefix-list']";
274 char xpath_value
[XPATH_MAXLEN
];
276 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
277 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
278 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
280 return nb_cli_apply_changes(vty
, NULL
);
284 no_match_ip_address_prefix_list
, no_match_ip_address_prefix_list_cmd
,
285 "no match ip address prefix-list [WORD]",
289 "Match address of route\n"
290 "Match entries of prefix-lists\n"
291 "IP prefix-list name\n")
293 const char *xpath
= "./match-condition[condition='ipv4-prefix-list']";
295 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
297 return nb_cli_apply_changes(vty
, NULL
);
301 match_ip_next_hop
, match_ip_next_hop_cmd
,
302 "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
305 "Match next-hop address of route\n"
306 "IP access-list number\n"
307 "IP access-list number (expanded range)\n"
308 "IP Access-list name\n")
310 const char *xpath
= "./match-condition[condition='ipv4-next-hop-list']";
311 char xpath_value
[XPATH_MAXLEN
+ 32];
312 int acln
= acll
? acll
: aclh
;
314 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
316 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name",
318 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
319 } else /* if (acll || aclh) */ {
320 if ((acln
>= 1 && acln
<= 99)
321 || (acln
>= 1300 && acln
<= 1999)) {
322 snprintf(xpath_value
, sizeof(xpath_value
),
323 "%s/access-list-num", xpath
);
326 * if ((acln >= 100 && acln <= 199)
327 * || (acln >= 2000 && acln <= 2699))
329 snprintf(xpath_value
, sizeof(xpath_value
),
330 "%s/access-list-num-extended", xpath
);
332 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
333 acll_str
? acll_str
: aclh_str
);
336 return nb_cli_apply_changes(vty
, NULL
);
340 no_match_ip_next_hop
, no_match_ip_next_hop_cmd
,
341 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
345 "Match address of route\n"
346 "IP access-list number\n"
347 "IP access-list number (expanded range)\n"
348 "IP Access-list name\n")
350 const char *xpath
= "./match-condition[condition='ipv4-next-hop-list']";
352 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
354 return nb_cli_apply_changes(vty
, NULL
);
358 match_ip_next_hop_prefix_list
,
359 match_ip_next_hop_prefix_list_cmd
,
360 "match ip next-hop prefix-list WORD$name",
363 "Match next-hop address of route\n"
364 "Match entries of prefix-lists\n"
365 "IP prefix-list name\n")
368 "./match-condition[condition='ipv4-next-hop-prefix-list']";
369 char xpath_value
[XPATH_MAXLEN
];
371 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
372 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
373 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
375 return nb_cli_apply_changes(vty
, NULL
);
379 no_match_ip_next_hop_prefix_list
,
380 no_match_ip_next_hop_prefix_list_cmd
,
381 "no match ip next-hop prefix-list [WORD]",
385 "Match next-hop address of route\n"
386 "Match entries of prefix-lists\n"
387 "IP prefix-list name\n")
390 "./match-condition[condition='ipv4-next-hop-prefix-list']";
392 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
394 return nb_cli_apply_changes(vty
, NULL
);
398 match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
399 "match ip next-hop type <blackhole>$type",
402 "Match next-hop address of route\n"
403 "Match entries by type\n"
406 const char *xpath
= "./match-condition[condition='ipv4-next-hop-type']";
407 char xpath_value
[XPATH_MAXLEN
];
409 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
410 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv4-next-hop-type",
412 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, type
);
414 return nb_cli_apply_changes(vty
, NULL
);
418 no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
419 "no match ip next-hop type [<blackhole>]",
420 NO_STR MATCH_STR IP_STR
421 "Match next-hop address of route\n"
422 "Match entries by type\n"
425 const char *xpath
= "./match-condition[condition='ipv4-next-hop-type']";
427 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
429 return nb_cli_apply_changes(vty
, NULL
);
433 match_ipv6_address
, match_ipv6_address_cmd
,
434 "match ipv6 address WORD$name",
437 "Match IPv6 address of route\n"
438 "IPv6 access-list name\n")
440 const char *xpath
= "./match-condition[condition='ipv6-address-list']";
441 char xpath_value
[XPATH_MAXLEN
];
443 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
444 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
445 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
447 return nb_cli_apply_changes(vty
, NULL
);
451 no_match_ipv6_address
, no_match_ipv6_address_cmd
,
452 "no match ipv6 address [WORD]",
456 "Match IPv6 address of route\n"
457 "IPv6 access-list name\n")
459 const char *xpath
= "./match-condition[condition='ipv6-address-list']";
461 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
463 return nb_cli_apply_changes(vty
, NULL
);
467 match_ipv6_address_prefix_list
, match_ipv6_address_prefix_list_cmd
,
468 "match ipv6 address prefix-list WORD$name",
471 "Match address of route\n"
472 "Match entries of prefix-lists\n"
473 "IP prefix-list name\n")
475 const char *xpath
= "./match-condition[condition='ipv6-prefix-list']";
476 char xpath_value
[XPATH_MAXLEN
];
478 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
479 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
480 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
482 return nb_cli_apply_changes(vty
, NULL
);
486 no_match_ipv6_address_prefix_list
,
487 no_match_ipv6_address_prefix_list_cmd
,
488 "no match ipv6 address prefix-list [WORD]",
492 "Match address of route\n"
493 "Match entries of prefix-lists\n"
494 "IP prefix-list name\n")
496 const char *xpath
= "./match-condition[condition='ipv6-prefix-list']";
498 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
500 return nb_cli_apply_changes(vty
, NULL
);
504 match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
505 "match ipv6 next-hop type <blackhole>$type",
507 "Match next-hop address of route\n"
508 "Match entries by type\n"
511 const char *xpath
= "./match-condition[condition='ipv6-next-hop-type']";
512 char xpath_value
[XPATH_MAXLEN
];
514 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
515 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv6-next-hop-type",
517 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, type
);
519 return nb_cli_apply_changes(vty
, NULL
);
523 no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
524 "no match ipv6 next-hop type [<blackhole>]",
525 NO_STR MATCH_STR IPV6_STR
526 "Match address of route\n"
527 "Match entries by type\n"
530 const char *xpath
= "./match-condition[condition='ipv6-next-hop-type']";
532 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
534 return nb_cli_apply_changes(vty
, NULL
);
538 match_metric
, match_metric_cmd
,
539 "match metric (0-4294967295)$metric",
541 "Match metric of route\n"
544 const char *xpath
= "./match-condition[condition='metric']";
545 char xpath_value
[XPATH_MAXLEN
];
547 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
548 snprintf(xpath_value
, sizeof(xpath_value
), "%s/metric", xpath
);
549 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, metric_str
);
551 return nb_cli_apply_changes(vty
, NULL
);
555 no_match_metric
, no_match_metric_cmd
,
556 "no match metric [(0-4294967295)]",
559 "Match metric of route\n"
562 const char *xpath
= "./match-condition[condition='metric']";
564 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
566 return nb_cli_apply_changes(vty
, NULL
);
570 match_tag
, match_tag_cmd
,
571 "match tag (1-4294967295)$tag",
573 "Match tag of route\n"
576 const char *xpath
= "./match-condition[condition='tag']";
577 char xpath_value
[XPATH_MAXLEN
];
579 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
580 snprintf(xpath_value
, sizeof(xpath_value
), "%s/tag", xpath
);
581 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, tag_str
);
583 return nb_cli_apply_changes(vty
, NULL
);
587 no_match_tag
, no_match_tag_cmd
,
588 "no match tag [(1-4294967295)]",
591 "Match tag of route\n"
594 const char *xpath
= "./match-condition[condition='tag']";
596 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
598 return nb_cli_apply_changes(vty
, NULL
);
601 void route_map_condition_show(struct vty
*vty
, struct lyd_node
*dnode
,
604 int condition
= yang_dnode_get_enum(dnode
, "./condition");
609 case 0: /* interface */
610 vty_out(vty
, " match interface %s\n",
611 yang_dnode_get_string(dnode
, "./interface"));
613 case 1: /* ipv4-address-list */
614 case 3: /* ipv4-next-hop-list */
616 if ((ln
= yang_dnode_get(dnode
, "./list-name")) != NULL
)
617 acl
= yang_dnode_get_string(ln
, NULL
);
618 else if ((ln
= yang_dnode_get(dnode
, "./access-list-num"))
620 acl
= yang_dnode_get_string(ln
, NULL
);
621 else if ((ln
= yang_dnode_get(dnode
,
622 "./access-list-num-extended"))
624 acl
= yang_dnode_get_string(ln
, NULL
);
630 vty_out(vty
, " match ip address %s\n", acl
);
633 vty_out(vty
, " match ip next-hop %s\n", acl
);
637 case 2: /* ipv4-prefix-list */
638 vty_out(vty
, " match ip address prefix-list %s\n",
639 yang_dnode_get_string(dnode
, "./list-name"));
641 case 4: /* ipv4-next-hop-prefix-list */
642 vty_out(vty
, " match ip next-hop prefix-list %s\n",
643 yang_dnode_get_string(dnode
, "./list-name"));
645 case 5: /* ipv4-next-hop-type */
646 vty_out(vty
, " match ip next-hop type %s\n",
647 yang_dnode_get_string(dnode
, "./ipv4-next-hop-type"));
649 case 6: /* ipv6-address-list */
650 vty_out(vty
, " match ipv6 address %s\n",
651 yang_dnode_get_string(dnode
, "./list-name"));
653 case 7: /* ipv6-prefix-list */
654 vty_out(vty
, " match ipv6 address prefix-list %s\n",
655 yang_dnode_get_string(dnode
, "./list-name"));
657 case 8: /* ipv6-next-hop-type */
658 vty_out(vty
, " match ipv6 next-hop type %s\n",
659 yang_dnode_get_string(dnode
, "./ipv6-next-hop-type"));
662 vty_out(vty
, " match metric %s\n",
663 yang_dnode_get_string(dnode
, "./metric"));
666 vty_out(vty
, " match tag %s\n",
667 yang_dnode_get_string(dnode
, "./tag"));
670 /* NOTHING: custom field, should be handled by daemon. */
676 set_ip_nexthop
, set_ip_nexthop_cmd
,
677 "set ip next-hop A.B.C.D$addr",
681 "IP address of next hop\n")
683 const char *xpath
= "./set-action[action='ipv4-next-hop']";
684 char xpath_value
[XPATH_MAXLEN
];
686 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
687 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv4-address", xpath
);
688 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, addr_str
);
690 return nb_cli_apply_changes(vty
, NULL
);
694 no_set_ip_nexthop
, no_set_ip_nexthop_cmd
,
695 "no set ip next-hop [A.B.C.D]",
700 "IP address of next hop\n")
702 const char *xpath
= "./set-action[action='ipv4-next-hop']";
704 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
706 return nb_cli_apply_changes(vty
, NULL
);
710 set_ipv6_nexthop_local
, set_ipv6_nexthop_local_cmd
,
711 "set ipv6 next-hop local X:X::X:X$addr",
714 "IPv6 next-hop address\n"
715 "IPv6 local address\n"
716 "IPv6 address of next hop\n")
718 const char *xpath
= "./set-action[action='ipv6-next-hop']";
719 char xpath_value
[XPATH_MAXLEN
];
721 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
722 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv6-address", xpath
);
723 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, addr_str
);
725 return nb_cli_apply_changes(vty
, NULL
);
729 no_set_ipv6_nexthop_local
, no_set_ipv6_nexthop_local_cmd
,
730 "no set ipv6 next-hop local [X:X::X:X]",
734 "IPv6 next-hop address\n"
735 "IPv6 local address\n"
736 "IPv6 address of next hop\n")
738 const char *xpath
= "./set-action[action='ipv6-next-hop']";
740 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
742 return nb_cli_apply_changes(vty
, NULL
);
746 set_metric
, set_metric_cmd
,
747 "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
749 "Metric value for destination routing protocol\n"
751 "Assign round trip time\n"
752 "Add round trip time\n"
753 "Subtract round trip time\n"
757 const char *xpath
= "./set-action[action='metric']";
758 char xpath_value
[XPATH_MAXLEN
];
761 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
763 snprintf(xpath_value
, sizeof(xpath_value
),
764 "%s/use-round-trip-time", xpath
);
765 snprintf(value
, sizeof(value
), "true");
767 snprintf(xpath_value
, sizeof(xpath_value
),
768 "%s/add-round-trip-time", xpath
);
769 snprintf(value
, sizeof(value
), "true");
771 snprintf(xpath_value
, sizeof(xpath_value
),
772 "%s/subtract-round-trip-time", xpath
);
773 snprintf(value
, sizeof(value
), "true");
774 } else if (ametric
) {
775 snprintf(xpath_value
, sizeof(xpath_value
), "%s/add-metric",
777 snprintf(value
, sizeof(value
), "true");
778 } else if (smetric
) {
779 snprintf(xpath_value
, sizeof(xpath_value
), "%s/subtract-metric",
781 snprintf(value
, sizeof(value
), "true");
783 snprintf(xpath_value
, sizeof(xpath_value
), "%s/value", xpath
);
784 snprintf(value
, sizeof(value
), "%lu", metric
);
786 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, value
);
788 return nb_cli_apply_changes(vty
, NULL
);
792 no_set_metric
, no_set_metric_cmd
,
793 "no set metric [(0-4294967295)]",
796 "Metric value for destination routing protocol\n"
799 const char *xpath
= "./set-action[action='metric']";
801 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
802 return nb_cli_apply_changes(vty
, NULL
);
806 set_tag
, set_tag_cmd
,
807 "set tag (1-4294967295)$tag",
809 "Tag value for routing protocol\n"
812 const char *xpath
= "./set-action[action='tag']";
813 char xpath_value
[XPATH_MAXLEN
];
815 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
816 snprintf(xpath_value
, sizeof(xpath_value
), "%s/tag", xpath
);
817 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, tag_str
);
819 return nb_cli_apply_changes(vty
, NULL
);
823 no_set_tag
, no_set_tag_cmd
,
824 "no set tag [(1-4294967295)]",
827 "Tag value for routing protocol\n"
830 const char *xpath
= "./set-action[action='tag']";
832 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
834 return nb_cli_apply_changes(vty
, NULL
);
837 void route_map_action_show(struct vty
*vty
, struct lyd_node
*dnode
,
840 int action
= yang_dnode_get_enum(dnode
, "./action");
843 case 0: /* ipv4-next-hop */
844 vty_out(vty
, " set ip next-hop %s\n",
845 yang_dnode_get_string(dnode
, "./ipv4-address"));
847 case 1: /* ipv6-next-hop */
848 vty_out(vty
, " set ipv6 next-hop local %s\n",
849 yang_dnode_get_string(dnode
, "./ipv6-address"));
852 if (yang_dnode_get(dnode
, "./use-round-trip-time")) {
853 vty_out(vty
, " set metric rtt\n");
854 } else if (yang_dnode_get(dnode
, "./add-round-trip-time")) {
855 vty_out(vty
, " set metric +rtt\n");
856 } else if (yang_dnode_get(dnode
, "./subtract-round-trip-time")) {
857 vty_out(vty
, " set metric -rtt\n");
858 } else if (yang_dnode_get(dnode
, "./add-metric")) {
859 vty_out(vty
, " set metric +metric\n");
860 } else if (yang_dnode_get(dnode
, "./subtract-metric")) {
861 vty_out(vty
, " set metric -metric\n");
863 vty_out(vty
, " set metric %s\n",
864 yang_dnode_get_string(dnode
, "./value"));
868 vty_out(vty
, " set tag %s\n",
869 yang_dnode_get_string(dnode
, "./tag"));
872 /* NOTHING: custom field, should be handled by daemon. */
878 rmap_onmatch_next
, rmap_onmatch_next_cmd
,
880 "Exit policy on matches\n"
883 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_MODIFY
, "next");
885 return nb_cli_apply_changes(vty
, NULL
);
889 no_rmap_onmatch_next
,
890 no_rmap_onmatch_next_cmd
,
893 "Exit policy on matches\n"
896 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_DESTROY
, NULL
);
898 return nb_cli_apply_changes(vty
, NULL
);
902 rmap_onmatch_goto
, rmap_onmatch_goto_cmd
,
903 "on-match goto (1-65535)$rm_num",
904 "Exit policy on matches\n"
905 "Goto Clause number\n"
908 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_MODIFY
, "goto");
909 nb_cli_enqueue_change(vty
, "./goto-value", NB_OP_MODIFY
, rm_num_str
);
911 return nb_cli_apply_changes(vty
, NULL
);
915 no_rmap_onmatch_goto
, no_rmap_onmatch_goto_cmd
,
918 "Exit policy on matches\n"
919 "Goto Clause number\n")
921 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_DESTROY
, NULL
);
923 return nb_cli_apply_changes(vty
, NULL
);
926 /* Cisco/GNU Zebra compatibility aliases */
928 rmap_onmatch_goto
, rmap_continue_cmd
,
929 "continue (1-65535)$rm_num",
930 "Continue on a different entry within the route-map\n"
931 "Route-map entry sequence number\n")
934 no_rmap_onmatch_goto
, no_rmap_continue_cmd
,
935 "no continue [(1-65535)]",
937 "Continue on a different entry within the route-map\n"
938 "Route-map entry sequence number\n")
940 void route_map_exit_policy_show(struct vty
*vty
, struct lyd_node
*dnode
,
943 int exit_policy
= yang_dnode_get_enum(dnode
, NULL
);
945 switch (exit_policy
) {
946 case 0: /* permit-or-deny */
947 /* NOTHING: default option. */
950 vty_out(vty
, " on-match next\n");
953 vty_out(vty
, " on-match goto %s\n",
954 yang_dnode_get_string(dnode
, "../goto-value"));
960 rmap_call
, rmap_call_cmd
,
962 "Jump to another Route-Map after match+set\n"
963 "Target route-map name\n")
965 nb_cli_enqueue_change(vty
, "./call", NB_OP_MODIFY
, name
);
967 return nb_cli_apply_changes(vty
, NULL
);
971 no_rmap_call
, no_rmap_call_cmd
,
974 "Jump to another Route-Map after match+set\n")
976 nb_cli_enqueue_change(vty
, "./call", NB_OP_DESTROY
, NULL
);
978 return nb_cli_apply_changes(vty
, NULL
);
981 void route_map_call_show(struct vty
*vty
, struct lyd_node
*dnode
,
984 vty_out(vty
, " call %s\n", yang_dnode_get_string(dnode
, NULL
));
988 rmap_description
, rmap_description_cmd
,
989 "description LINE...",
990 "Route-map comment\n"
991 "Comment describing this route-map rule\n")
996 desc
= argv_concat(argv
, argc
, 1);
997 nb_cli_enqueue_change(vty
, "./description", NB_OP_MODIFY
, desc
);
998 rv
= nb_cli_apply_changes(vty
, NULL
);
999 XFREE(MTYPE_TMP
, desc
);
1004 DEFUN (no_rmap_description
,
1005 no_rmap_description_cmd
,
1008 "Route-map comment\n")
1010 nb_cli_enqueue_change(vty
, "./description", NB_OP_DESTROY
, NULL
);
1012 return nb_cli_apply_changes(vty
, NULL
);
1015 void route_map_description_show(struct vty
*vty
, struct lyd_node
*dnode
,
1018 vty_out(vty
, " description %s\n", yang_dnode_get_string(dnode
, NULL
));
1021 static int route_map_config_write(struct vty
*vty
)
1023 struct lyd_node
*dnode
;
1026 dnode
= yang_dnode_get(running_config
->dnode
,
1027 "/frr-route-map:lib");
1029 nb_cli_show_dnode_cmds(vty
, dnode
, false);
1036 /* Route map node structure. */
1037 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
1039 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
1041 struct route_map
*map
;
1043 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1044 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
1047 static const struct cmd_variable_handler rmap_var_handlers
[] = {
1048 {.varname
= "route_map", .completions
= rmap_autocomplete
},
1049 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
1050 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
1051 {.completions
= NULL
}
1054 void route_map_cli_init(void)
1056 /* Auto complete handler. */
1057 cmd_variable_handler_register(rmap_var_handlers
);
1060 install_node(&rmap_node
, route_map_config_write
);
1061 install_default(RMAP_NODE
);
1062 install_element(CONFIG_NODE
, &route_map_cmd
);
1063 install_element(CONFIG_NODE
, &no_route_map_cmd
);
1064 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
1066 /* Install the on-match stuff */
1067 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
1068 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
1069 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
1070 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
1071 install_element(RMAP_NODE
, &rmap_continue_cmd
);
1072 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
1074 /* Install the call stuff. */
1075 install_element(RMAP_NODE
, &rmap_call_cmd
);
1076 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
1078 /* Install description commands. */
1079 install_element(RMAP_NODE
, &rmap_description_cmd
);
1080 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
1082 /* Install 'match' commands. */
1083 install_element(RMAP_NODE
, &match_interface_cmd
);
1084 install_element(RMAP_NODE
, &no_match_interface_cmd
);
1086 install_element(RMAP_NODE
, &match_ip_address_cmd
);
1087 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
1089 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
1090 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
1092 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
1093 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
1095 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
1096 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
1098 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
1099 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
1101 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
1102 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
1104 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
1105 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
1107 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
1108 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
1110 install_element(RMAP_NODE
, &match_metric_cmd
);
1111 install_element(RMAP_NODE
, &no_match_metric_cmd
);
1113 install_element(RMAP_NODE
, &match_tag_cmd
);
1114 install_element(RMAP_NODE
, &no_match_tag_cmd
);
1116 /* Install 'set' commands. */
1117 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
1118 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
1120 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
1121 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
1123 install_element(RMAP_NODE
, &set_metric_cmd
);
1124 install_element(RMAP_NODE
, &no_set_metric_cmd
);
1126 install_element(RMAP_NODE
, &set_tag_cmd
);
1127 install_element(RMAP_NODE
, &no_set_tag_cmd
);