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");
151 /* Zebra specific match conditions. */
152 SKIP_RULE("ip address prefix-len");
153 SKIP_RULE("ipv6 address prefix-len");
154 SKIP_RULE("ip next-hop prefix-len");
155 SKIP_RULE("source-protocol");
156 SKIP_RULE("source-instance");
158 vty_out(vty
, " match %s %s\n", rmr
->cmd
->str
,
159 rmr
->rule_str
? rmr
->rule_str
: "");
162 /* Print route map `set` for old CLI users. */
163 for (rmr
= rmi
->set_list
.head
; rmr
; rmr
= rmr
->next
) {
164 /* Skip all sets implemented by northbound. */
167 /* Zebra specific set actions. */
170 vty_out(vty
, " set %s %s\n", rmr
->cmd
->str
,
171 rmr
->rule_str
? rmr
->rule_str
: "");
177 void route_map_instance_show_end(struct vty
*vty
, struct lyd_node
*dnode
)
183 match_interface
, match_interface_cmd
,
184 "match interface IFNAME",
186 "Match first hop interface of route\n"
189 const char *xpath
= "./match-condition[condition='interface']";
190 char xpath_value
[XPATH_MAXLEN
];
192 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
193 snprintf(xpath_value
, sizeof(xpath_value
), "%s/interface", xpath
);
194 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, ifname
);
196 return nb_cli_apply_changes(vty
, NULL
);
200 no_match_interface
, no_match_interface_cmd
,
201 "no match interface [IFNAME]",
204 "Match first hop interface of route\n"
207 const char *xpath
= "./match-condition[condition='interface']";
209 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
211 return nb_cli_apply_changes(vty
, NULL
);
215 match_ip_address
, match_ip_address_cmd
,
216 "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
219 "Match address of route\n"
220 "IP access-list number\n"
221 "IP access-list number (expanded range)\n"
222 "IP Access-list name\n")
224 const char *xpath
= "./match-condition[condition='ipv4-address-list']";
225 char xpath_value
[XPATH_MAXLEN
+ 32];
226 int acln
= acll
? acll
: aclh
;
228 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
230 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name",
232 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
233 } else /* if (acll || aclh) */ {
234 if ((acln
>= 1 && acln
<= 99)
235 || (acln
>= 1300 && acln
<= 1999)) {
236 snprintf(xpath_value
, sizeof(xpath_value
),
237 "%s/access-list-num", xpath
);
240 * if ((acln >= 100 && acln <= 199)
241 * || (acln >= 2000 && acln <= 2699))
243 snprintf(xpath_value
, sizeof(xpath_value
),
244 "%s/access-list-num-extended", xpath
);
246 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
247 acll_str
? acll_str
: aclh_str
);
250 return nb_cli_apply_changes(vty
, NULL
);
254 no_match_ip_address
, no_match_ip_address_cmd
,
255 "no match ip address [<(1-199)|(1300-2699)|WORD>]",
259 "Match address of route\n"
260 "IP access-list number\n"
261 "IP access-list number (expanded range)\n"
262 "IP Access-list name\n")
264 const char *xpath
= "./match-condition[condition='ipv4-address-list']";
266 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
268 return nb_cli_apply_changes(vty
, NULL
);
272 match_ip_address_prefix_list
,
273 match_ip_address_prefix_list_cmd
,
274 "match ip address prefix-list WORD$name",
277 "Match address of route\n"
278 "Match entries of prefix-lists\n"
279 "IP prefix-list name\n")
281 const char *xpath
= "./match-condition[condition='ipv4-prefix-list']";
282 char xpath_value
[XPATH_MAXLEN
];
284 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
285 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
286 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
288 return nb_cli_apply_changes(vty
, NULL
);
292 no_match_ip_address_prefix_list
, no_match_ip_address_prefix_list_cmd
,
293 "no match ip address prefix-list [WORD]",
297 "Match address of route\n"
298 "Match entries of prefix-lists\n"
299 "IP prefix-list name\n")
301 const char *xpath
= "./match-condition[condition='ipv4-prefix-list']";
303 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
305 return nb_cli_apply_changes(vty
, NULL
);
309 match_ip_next_hop
, match_ip_next_hop_cmd
,
310 "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
313 "Match next-hop address of route\n"
314 "IP access-list number\n"
315 "IP access-list number (expanded range)\n"
316 "IP Access-list name\n")
318 const char *xpath
= "./match-condition[condition='ipv4-next-hop-list']";
319 char xpath_value
[XPATH_MAXLEN
+ 32];
320 int acln
= acll
? acll
: aclh
;
322 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
324 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name",
326 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
327 } else /* if (acll || aclh) */ {
328 if ((acln
>= 1 && acln
<= 99)
329 || (acln
>= 1300 && acln
<= 1999)) {
330 snprintf(xpath_value
, sizeof(xpath_value
),
331 "%s/access-list-num", xpath
);
334 * if ((acln >= 100 && acln <= 199)
335 * || (acln >= 2000 && acln <= 2699))
337 snprintf(xpath_value
, sizeof(xpath_value
),
338 "%s/access-list-num-extended", xpath
);
340 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
,
341 acll_str
? acll_str
: aclh_str
);
344 return nb_cli_apply_changes(vty
, NULL
);
348 no_match_ip_next_hop
, no_match_ip_next_hop_cmd
,
349 "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
353 "Match address of route\n"
354 "IP access-list number\n"
355 "IP access-list number (expanded range)\n"
356 "IP Access-list name\n")
358 const char *xpath
= "./match-condition[condition='ipv4-next-hop-list']";
360 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
362 return nb_cli_apply_changes(vty
, NULL
);
366 match_ip_next_hop_prefix_list
,
367 match_ip_next_hop_prefix_list_cmd
,
368 "match ip next-hop prefix-list WORD$name",
371 "Match next-hop address of route\n"
372 "Match entries of prefix-lists\n"
373 "IP prefix-list name\n")
376 "./match-condition[condition='ipv4-next-hop-prefix-list']";
377 char xpath_value
[XPATH_MAXLEN
];
379 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
380 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
381 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
383 return nb_cli_apply_changes(vty
, NULL
);
387 no_match_ip_next_hop_prefix_list
,
388 no_match_ip_next_hop_prefix_list_cmd
,
389 "no match ip next-hop prefix-list [WORD]",
393 "Match next-hop address of route\n"
394 "Match entries of prefix-lists\n"
395 "IP prefix-list name\n")
398 "./match-condition[condition='ipv4-next-hop-prefix-list']";
400 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
402 return nb_cli_apply_changes(vty
, NULL
);
406 match_ip_next_hop_type
, match_ip_next_hop_type_cmd
,
407 "match ip next-hop type <blackhole>$type",
410 "Match next-hop address of route\n"
411 "Match entries by type\n"
414 const char *xpath
= "./match-condition[condition='ipv4-next-hop-type']";
415 char xpath_value
[XPATH_MAXLEN
];
417 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
418 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv4-next-hop-type",
420 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, type
);
422 return nb_cli_apply_changes(vty
, NULL
);
426 no_match_ip_next_hop_type
, no_match_ip_next_hop_type_cmd
,
427 "no match ip next-hop type [<blackhole>]",
428 NO_STR MATCH_STR IP_STR
429 "Match next-hop address of route\n"
430 "Match entries by type\n"
433 const char *xpath
= "./match-condition[condition='ipv4-next-hop-type']";
435 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
437 return nb_cli_apply_changes(vty
, NULL
);
441 match_ipv6_address
, match_ipv6_address_cmd
,
442 "match ipv6 address WORD$name",
445 "Match IPv6 address of route\n"
446 "IPv6 access-list name\n")
448 const char *xpath
= "./match-condition[condition='ipv6-address-list']";
449 char xpath_value
[XPATH_MAXLEN
];
451 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
452 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
453 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
455 return nb_cli_apply_changes(vty
, NULL
);
459 no_match_ipv6_address
, no_match_ipv6_address_cmd
,
460 "no match ipv6 address [WORD]",
464 "Match IPv6 address of route\n"
465 "IPv6 access-list name\n")
467 const char *xpath
= "./match-condition[condition='ipv6-address-list']";
469 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
471 return nb_cli_apply_changes(vty
, NULL
);
475 match_ipv6_address_prefix_list
, match_ipv6_address_prefix_list_cmd
,
476 "match ipv6 address prefix-list WORD$name",
479 "Match address of route\n"
480 "Match entries of prefix-lists\n"
481 "IP prefix-list name\n")
483 const char *xpath
= "./match-condition[condition='ipv6-prefix-list']";
484 char xpath_value
[XPATH_MAXLEN
];
486 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
487 snprintf(xpath_value
, sizeof(xpath_value
), "%s/list-name", xpath
);
488 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, name
);
490 return nb_cli_apply_changes(vty
, NULL
);
494 no_match_ipv6_address_prefix_list
,
495 no_match_ipv6_address_prefix_list_cmd
,
496 "no match ipv6 address prefix-list [WORD]",
500 "Match address of route\n"
501 "Match entries of prefix-lists\n"
502 "IP prefix-list name\n")
504 const char *xpath
= "./match-condition[condition='ipv6-prefix-list']";
506 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
508 return nb_cli_apply_changes(vty
, NULL
);
512 match_ipv6_next_hop_type
, match_ipv6_next_hop_type_cmd
,
513 "match ipv6 next-hop type <blackhole>$type",
515 "Match next-hop address of route\n"
516 "Match entries by type\n"
519 const char *xpath
= "./match-condition[condition='ipv6-next-hop-type']";
520 char xpath_value
[XPATH_MAXLEN
];
522 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
523 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv6-next-hop-type",
525 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, type
);
527 return nb_cli_apply_changes(vty
, NULL
);
531 no_match_ipv6_next_hop_type
, no_match_ipv6_next_hop_type_cmd
,
532 "no match ipv6 next-hop type [<blackhole>]",
533 NO_STR MATCH_STR IPV6_STR
534 "Match address of route\n"
535 "Match entries by type\n"
538 const char *xpath
= "./match-condition[condition='ipv6-next-hop-type']";
540 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
542 return nb_cli_apply_changes(vty
, NULL
);
546 match_metric
, match_metric_cmd
,
547 "match metric (0-4294967295)$metric",
549 "Match metric of route\n"
552 const char *xpath
= "./match-condition[condition='metric']";
553 char xpath_value
[XPATH_MAXLEN
];
555 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
556 snprintf(xpath_value
, sizeof(xpath_value
), "%s/metric", xpath
);
557 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, metric_str
);
559 return nb_cli_apply_changes(vty
, NULL
);
563 no_match_metric
, no_match_metric_cmd
,
564 "no match metric [(0-4294967295)]",
567 "Match metric of route\n"
570 const char *xpath
= "./match-condition[condition='metric']";
572 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
574 return nb_cli_apply_changes(vty
, NULL
);
578 match_tag
, match_tag_cmd
,
579 "match tag (1-4294967295)$tag",
581 "Match tag of route\n"
584 const char *xpath
= "./match-condition[condition='tag']";
585 char xpath_value
[XPATH_MAXLEN
];
587 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
588 snprintf(xpath_value
, sizeof(xpath_value
), "%s/tag", xpath
);
589 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, tag_str
);
591 return nb_cli_apply_changes(vty
, NULL
);
595 no_match_tag
, no_match_tag_cmd
,
596 "no match tag [(1-4294967295)]",
599 "Match tag of route\n"
602 const char *xpath
= "./match-condition[condition='tag']";
604 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
606 return nb_cli_apply_changes(vty
, NULL
);
609 void route_map_condition_show(struct vty
*vty
, struct lyd_node
*dnode
,
612 int condition
= yang_dnode_get_enum(dnode
, "./condition");
617 case 0: /* interface */
618 vty_out(vty
, " match interface %s\n",
619 yang_dnode_get_string(dnode
, "./interface"));
621 case 1: /* ipv4-address-list */
622 case 3: /* ipv4-next-hop-list */
624 if ((ln
= yang_dnode_get(dnode
, "./list-name")) != NULL
)
625 acl
= yang_dnode_get_string(ln
, NULL
);
626 else if ((ln
= yang_dnode_get(dnode
, "./access-list-num"))
628 acl
= yang_dnode_get_string(ln
, NULL
);
629 else if ((ln
= yang_dnode_get(dnode
,
630 "./access-list-num-extended"))
632 acl
= yang_dnode_get_string(ln
, NULL
);
638 vty_out(vty
, " match ip address %s\n", acl
);
641 vty_out(vty
, " match ip next-hop %s\n", acl
);
645 case 2: /* ipv4-prefix-list */
646 vty_out(vty
, " match ip address prefix-list %s\n",
647 yang_dnode_get_string(dnode
, "./list-name"));
649 case 4: /* ipv4-next-hop-prefix-list */
650 vty_out(vty
, " match ip next-hop prefix-list %s\n",
651 yang_dnode_get_string(dnode
, "./list-name"));
653 case 5: /* ipv4-next-hop-type */
654 vty_out(vty
, " match ip next-hop type %s\n",
655 yang_dnode_get_string(dnode
, "./ipv4-next-hop-type"));
657 case 6: /* ipv6-address-list */
658 vty_out(vty
, " match ipv6 address %s\n",
659 yang_dnode_get_string(dnode
, "./list-name"));
661 case 7: /* ipv6-prefix-list */
662 vty_out(vty
, " match ipv6 address prefix-list %s\n",
663 yang_dnode_get_string(dnode
, "./list-name"));
665 case 8: /* ipv6-next-hop-type */
666 vty_out(vty
, " match ipv6 next-hop type %s\n",
667 yang_dnode_get_string(dnode
, "./ipv6-next-hop-type"));
670 vty_out(vty
, " match metric %s\n",
671 yang_dnode_get_string(dnode
, "./metric"));
674 vty_out(vty
, " match tag %s\n",
675 yang_dnode_get_string(dnode
, "./tag"));
677 case 100: /* ipv4-prefix-length */
678 vty_out(vty
, " match ip address prefix-len %s\n",
679 yang_dnode_get_string(dnode
,"./frr-zebra:ipv4-prefix-length"));
681 case 101: /* ipv6-prefix-length */
682 vty_out(vty
, " match ipv6 address prefix-len %s\n",
683 yang_dnode_get_string(dnode
, "./frr-zebra:ipv6-prefix-length"));
685 case 102: /* ipv4-next-hop-prefix-length */
686 vty_out(vty
, " match ip next-hop prefix-len %s\n",
687 yang_dnode_get_string(dnode
, "./frr-zebra:ipv4-prefix-length"));
689 case 103: /* source-protocol */
690 vty_out(vty
, " match source-protocol %s\n",
691 yang_dnode_get_string(dnode
, "./frr-zebra:source-protocol"));
693 case 104: /* source-instance */
694 vty_out(vty
, " match source-instance %s\n",
695 yang_dnode_get_string(dnode
, "./frr-zebra:source-instance"));
701 set_ip_nexthop
, set_ip_nexthop_cmd
,
702 "set ip next-hop A.B.C.D$addr",
706 "IP address of next hop\n")
708 const char *xpath
= "./set-action[action='ipv4-next-hop']";
709 char xpath_value
[XPATH_MAXLEN
];
711 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
712 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv4-address", xpath
);
713 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, addr_str
);
715 return nb_cli_apply_changes(vty
, NULL
);
719 no_set_ip_nexthop
, no_set_ip_nexthop_cmd
,
720 "no set ip next-hop [A.B.C.D]",
725 "IP address of next hop\n")
727 const char *xpath
= "./set-action[action='ipv4-next-hop']";
729 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
731 return nb_cli_apply_changes(vty
, NULL
);
735 set_ipv6_nexthop_local
, set_ipv6_nexthop_local_cmd
,
736 "set ipv6 next-hop local X:X::X:X$addr",
739 "IPv6 next-hop address\n"
740 "IPv6 local address\n"
741 "IPv6 address of next hop\n")
743 const char *xpath
= "./set-action[action='ipv6-next-hop']";
744 char xpath_value
[XPATH_MAXLEN
];
746 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
747 snprintf(xpath_value
, sizeof(xpath_value
), "%s/ipv6-address", xpath
);
748 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, addr_str
);
750 return nb_cli_apply_changes(vty
, NULL
);
754 no_set_ipv6_nexthop_local
, no_set_ipv6_nexthop_local_cmd
,
755 "no set ipv6 next-hop local [X:X::X:X]",
759 "IPv6 next-hop address\n"
760 "IPv6 local address\n"
761 "IPv6 address of next hop\n")
763 const char *xpath
= "./set-action[action='ipv6-next-hop']";
765 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
767 return nb_cli_apply_changes(vty
, NULL
);
771 set_metric
, set_metric_cmd
,
772 "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
774 "Metric value for destination routing protocol\n"
776 "Assign round trip time\n"
777 "Add round trip time\n"
778 "Subtract round trip time\n"
782 const char *xpath
= "./set-action[action='metric']";
783 char xpath_value
[XPATH_MAXLEN
];
786 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
788 snprintf(xpath_value
, sizeof(xpath_value
),
789 "%s/use-round-trip-time", xpath
);
790 snprintf(value
, sizeof(value
), "true");
792 snprintf(xpath_value
, sizeof(xpath_value
),
793 "%s/add-round-trip-time", xpath
);
794 snprintf(value
, sizeof(value
), "true");
796 snprintf(xpath_value
, sizeof(xpath_value
),
797 "%s/subtract-round-trip-time", xpath
);
798 snprintf(value
, sizeof(value
), "true");
799 } else if (ametric
) {
800 snprintf(xpath_value
, sizeof(xpath_value
), "%s/add-metric",
802 snprintf(value
, sizeof(value
), "true");
803 } else if (smetric
) {
804 snprintf(xpath_value
, sizeof(xpath_value
), "%s/subtract-metric",
806 snprintf(value
, sizeof(value
), "true");
808 snprintf(xpath_value
, sizeof(xpath_value
), "%s/value", xpath
);
809 snprintf(value
, sizeof(value
), "%lu", metric
);
811 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, value
);
813 return nb_cli_apply_changes(vty
, NULL
);
817 no_set_metric
, no_set_metric_cmd
,
818 "no set metric [(0-4294967295)]",
821 "Metric value for destination routing protocol\n"
824 const char *xpath
= "./set-action[action='metric']";
826 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
827 return nb_cli_apply_changes(vty
, NULL
);
831 set_tag
, set_tag_cmd
,
832 "set tag (1-4294967295)$tag",
834 "Tag value for routing protocol\n"
837 const char *xpath
= "./set-action[action='tag']";
838 char xpath_value
[XPATH_MAXLEN
];
840 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
841 snprintf(xpath_value
, sizeof(xpath_value
), "%s/tag", xpath
);
842 nb_cli_enqueue_change(vty
, xpath_value
, NB_OP_MODIFY
, tag_str
);
844 return nb_cli_apply_changes(vty
, NULL
);
848 no_set_tag
, no_set_tag_cmd
,
849 "no set tag [(1-4294967295)]",
852 "Tag value for routing protocol\n"
855 const char *xpath
= "./set-action[action='tag']";
857 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
859 return nb_cli_apply_changes(vty
, NULL
);
862 void route_map_action_show(struct vty
*vty
, struct lyd_node
*dnode
,
865 int action
= yang_dnode_get_enum(dnode
, "./action");
868 case 0: /* ipv4-next-hop */
869 vty_out(vty
, " set ip next-hop %s\n",
870 yang_dnode_get_string(dnode
, "./ipv4-address"));
872 case 1: /* ipv6-next-hop */
873 vty_out(vty
, " set ipv6 next-hop local %s\n",
874 yang_dnode_get_string(dnode
, "./ipv6-address"));
877 if (yang_dnode_get(dnode
, "./use-round-trip-time")) {
878 vty_out(vty
, " set metric rtt\n");
879 } else if (yang_dnode_get(dnode
, "./add-round-trip-time")) {
880 vty_out(vty
, " set metric +rtt\n");
881 } else if (yang_dnode_get(dnode
, "./subtract-round-trip-time")) {
882 vty_out(vty
, " set metric -rtt\n");
883 } else if (yang_dnode_get(dnode
, "./add-metric")) {
884 vty_out(vty
, " set metric +metric\n");
885 } else if (yang_dnode_get(dnode
, "./subtract-metric")) {
886 vty_out(vty
, " set metric -metric\n");
888 vty_out(vty
, " set metric %s\n",
889 yang_dnode_get_string(dnode
, "./value"));
893 vty_out(vty
, " set tag %s\n",
894 yang_dnode_get_string(dnode
, "./tag"));
896 case 100: /* source */
897 if (yang_dnode_exists(dnode
, "./frr-zebra:source-v4"))
898 vty_out(vty
, " set src %s\n",
899 yang_dnode_get_string(dnode
, "./frr-zebra:source-v4"));
901 vty_out(vty
, " set src %s\n",
902 yang_dnode_get_string(dnode
, "./frr-zebra:source-v6"));
908 rmap_onmatch_next
, rmap_onmatch_next_cmd
,
910 "Exit policy on matches\n"
913 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_MODIFY
, "next");
915 return nb_cli_apply_changes(vty
, NULL
);
919 no_rmap_onmatch_next
,
920 no_rmap_onmatch_next_cmd
,
923 "Exit policy on matches\n"
926 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_DESTROY
, NULL
);
928 return nb_cli_apply_changes(vty
, NULL
);
932 rmap_onmatch_goto
, rmap_onmatch_goto_cmd
,
933 "on-match goto (1-65535)$rm_num",
934 "Exit policy on matches\n"
935 "Goto Clause number\n"
938 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_MODIFY
, "goto");
939 nb_cli_enqueue_change(vty
, "./goto-value", NB_OP_MODIFY
, rm_num_str
);
941 return nb_cli_apply_changes(vty
, NULL
);
945 no_rmap_onmatch_goto
, no_rmap_onmatch_goto_cmd
,
948 "Exit policy on matches\n"
949 "Goto Clause number\n")
951 nb_cli_enqueue_change(vty
, "./exit-policy", NB_OP_DESTROY
, NULL
);
953 return nb_cli_apply_changes(vty
, NULL
);
956 /* Cisco/GNU Zebra compatibility aliases */
958 rmap_onmatch_goto
, rmap_continue_cmd
,
959 "continue (1-65535)$rm_num",
960 "Continue on a different entry within the route-map\n"
961 "Route-map entry sequence number\n")
964 no_rmap_onmatch_goto
, no_rmap_continue_cmd
,
965 "no continue [(1-65535)]",
967 "Continue on a different entry within the route-map\n"
968 "Route-map entry sequence number\n")
970 void route_map_exit_policy_show(struct vty
*vty
, struct lyd_node
*dnode
,
973 int exit_policy
= yang_dnode_get_enum(dnode
, NULL
);
975 switch (exit_policy
) {
976 case 0: /* permit-or-deny */
977 /* NOTHING: default option. */
980 vty_out(vty
, " on-match next\n");
983 vty_out(vty
, " on-match goto %s\n",
984 yang_dnode_get_string(dnode
, "../goto-value"));
990 rmap_call
, rmap_call_cmd
,
992 "Jump to another Route-Map after match+set\n"
993 "Target route-map name\n")
995 nb_cli_enqueue_change(vty
, "./call", NB_OP_MODIFY
, name
);
997 return nb_cli_apply_changes(vty
, NULL
);
1001 no_rmap_call
, no_rmap_call_cmd
,
1004 "Jump to another Route-Map after match+set\n")
1006 nb_cli_enqueue_change(vty
, "./call", NB_OP_DESTROY
, NULL
);
1008 return nb_cli_apply_changes(vty
, NULL
);
1011 void route_map_call_show(struct vty
*vty
, struct lyd_node
*dnode
,
1014 vty_out(vty
, " call %s\n", yang_dnode_get_string(dnode
, NULL
));
1018 rmap_description
, rmap_description_cmd
,
1019 "description LINE...",
1020 "Route-map comment\n"
1021 "Comment describing this route-map rule\n")
1026 desc
= argv_concat(argv
, argc
, 1);
1027 nb_cli_enqueue_change(vty
, "./description", NB_OP_MODIFY
, desc
);
1028 rv
= nb_cli_apply_changes(vty
, NULL
);
1029 XFREE(MTYPE_TMP
, desc
);
1034 DEFUN (no_rmap_description
,
1035 no_rmap_description_cmd
,
1038 "Route-map comment\n")
1040 nb_cli_enqueue_change(vty
, "./description", NB_OP_DESTROY
, NULL
);
1042 return nb_cli_apply_changes(vty
, NULL
);
1045 void route_map_description_show(struct vty
*vty
, struct lyd_node
*dnode
,
1048 vty_out(vty
, " description %s\n", yang_dnode_get_string(dnode
, NULL
));
1051 static int route_map_config_write(struct vty
*vty
)
1053 struct lyd_node
*dnode
;
1056 dnode
= yang_dnode_get(running_config
->dnode
,
1057 "/frr-route-map:lib");
1059 nb_cli_show_dnode_cmds(vty
, dnode
, false);
1066 /* Route map node structure. */
1067 static struct cmd_node rmap_node
= {RMAP_NODE
, "%s(config-route-map)# ", 1};
1069 static void rmap_autocomplete(vector comps
, struct cmd_token
*token
)
1071 struct route_map
*map
;
1073 for (map
= route_map_master
.head
; map
; map
= map
->next
)
1074 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, map
->name
));
1077 static const struct cmd_variable_handler rmap_var_handlers
[] = {
1078 {.varname
= "route_map", .completions
= rmap_autocomplete
},
1079 {.tokenname
= "ROUTEMAP_NAME", .completions
= rmap_autocomplete
},
1080 {.tokenname
= "RMAP_NAME", .completions
= rmap_autocomplete
},
1081 {.completions
= NULL
}
1084 void route_map_cli_init(void)
1086 /* Auto complete handler. */
1087 cmd_variable_handler_register(rmap_var_handlers
);
1090 install_node(&rmap_node
, route_map_config_write
);
1091 install_default(RMAP_NODE
);
1092 install_element(CONFIG_NODE
, &route_map_cmd
);
1093 install_element(CONFIG_NODE
, &no_route_map_cmd
);
1094 install_element(CONFIG_NODE
, &no_route_map_all_cmd
);
1096 /* Install the on-match stuff */
1097 install_element(RMAP_NODE
, &rmap_onmatch_next_cmd
);
1098 install_element(RMAP_NODE
, &no_rmap_onmatch_next_cmd
);
1099 install_element(RMAP_NODE
, &rmap_onmatch_goto_cmd
);
1100 install_element(RMAP_NODE
, &no_rmap_onmatch_goto_cmd
);
1101 install_element(RMAP_NODE
, &rmap_continue_cmd
);
1102 install_element(RMAP_NODE
, &no_rmap_continue_cmd
);
1104 /* Install the call stuff. */
1105 install_element(RMAP_NODE
, &rmap_call_cmd
);
1106 install_element(RMAP_NODE
, &no_rmap_call_cmd
);
1108 /* Install description commands. */
1109 install_element(RMAP_NODE
, &rmap_description_cmd
);
1110 install_element(RMAP_NODE
, &no_rmap_description_cmd
);
1112 /* Install 'match' commands. */
1113 install_element(RMAP_NODE
, &match_interface_cmd
);
1114 install_element(RMAP_NODE
, &no_match_interface_cmd
);
1116 install_element(RMAP_NODE
, &match_ip_address_cmd
);
1117 install_element(RMAP_NODE
, &no_match_ip_address_cmd
);
1119 install_element(RMAP_NODE
, &match_ip_address_prefix_list_cmd
);
1120 install_element(RMAP_NODE
, &no_match_ip_address_prefix_list_cmd
);
1122 install_element(RMAP_NODE
, &match_ip_next_hop_cmd
);
1123 install_element(RMAP_NODE
, &no_match_ip_next_hop_cmd
);
1125 install_element(RMAP_NODE
, &match_ip_next_hop_prefix_list_cmd
);
1126 install_element(RMAP_NODE
, &no_match_ip_next_hop_prefix_list_cmd
);
1128 install_element(RMAP_NODE
, &match_ip_next_hop_type_cmd
);
1129 install_element(RMAP_NODE
, &no_match_ip_next_hop_type_cmd
);
1131 install_element(RMAP_NODE
, &match_ipv6_address_cmd
);
1132 install_element(RMAP_NODE
, &no_match_ipv6_address_cmd
);
1134 install_element(RMAP_NODE
, &match_ipv6_address_prefix_list_cmd
);
1135 install_element(RMAP_NODE
, &no_match_ipv6_address_prefix_list_cmd
);
1137 install_element(RMAP_NODE
, &match_ipv6_next_hop_type_cmd
);
1138 install_element(RMAP_NODE
, &no_match_ipv6_next_hop_type_cmd
);
1140 install_element(RMAP_NODE
, &match_metric_cmd
);
1141 install_element(RMAP_NODE
, &no_match_metric_cmd
);
1143 install_element(RMAP_NODE
, &match_tag_cmd
);
1144 install_element(RMAP_NODE
, &no_match_tag_cmd
);
1146 /* Install 'set' commands. */
1147 install_element(RMAP_NODE
, &set_ip_nexthop_cmd
);
1148 install_element(RMAP_NODE
, &no_set_ip_nexthop_cmd
);
1150 install_element(RMAP_NODE
, &set_ipv6_nexthop_local_cmd
);
1151 install_element(RMAP_NODE
, &no_set_ipv6_nexthop_local_cmd
);
1153 install_element(RMAP_NODE
, &set_metric_cmd
);
1154 install_element(RMAP_NODE
, &no_set_metric_cmd
);
1156 install_element(RMAP_NODE
, &set_tag_cmd
);
1157 install_element(RMAP_NODE
, &no_set_tag_cmd
);