]> git.proxmox.com Git - mirror_frr.git/blame - lib/routemap_cli.c
bgpd: fix missing doc string in evpn
[mirror_frr.git] / lib / routemap_cli.c
CommitLineData
2b3e4807
RZ
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
ca77b518 42DEFPY_YANG_NOSH(
2b3e4807
RZ
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{
e324ef43
RZ
49 struct route_map_index *rmi;
50 struct route_map *rm;
51 int action_type;
2b3e4807
RZ
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);
e324ef43 69 if (rv == CMD_SUCCESS) {
2b3e4807
RZ
70 VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
71
e324ef43 72 /* Add support for non-migrated route map users. */
b855e95f 73 nb_cli_pending_commit_check(vty);
e324ef43
RZ
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
2b3e4807
RZ
80 return rv;
81}
82
ca77b518 83DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 98DEFPY_YANG(
2b3e4807
RZ
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
116void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
117 bool show_defaults)
118{
e324ef43
RZ
119 const struct route_map_rule *rmr;
120 const struct route_map_index *rmi;
2b3e4807
RZ
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);
e324ef43
RZ
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");
f42cc965
RZ
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");
e324ef43
RZ
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");
f42cc965
RZ
168 /* Zebra specific set actions. */
169 SKIP_RULE("src");
e324ef43
RZ
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
2b3e4807
RZ
176}
177
178void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
179{
180 vty_out(vty, "!\n");
181}
182
ca77b518 183DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 200DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 215DEFPY_YANG(
2b3e4807 216 match_ip_address, match_ip_address_cmd,
375d157f 217 "match ip address <(1-199)|(1300-2699)|WORD>$name",
2b3e4807
RZ
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];
2b3e4807
RZ
227
228 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
375d157f
RZ
229 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
230 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
2b3e4807
RZ
231
232 return nb_cli_apply_changes(vty, NULL);
233}
234
ca77b518 235DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 253DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 273DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 290DEFPY_YANG(
2b3e4807 291 match_ip_next_hop, match_ip_next_hop_cmd,
375d157f 292 "match ip next-hop <(1-199)|(1300-2699)|WORD>$name",
2b3e4807
RZ
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];
2b3e4807
RZ
302
303 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
375d157f
RZ
304 snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
305 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
2b3e4807
RZ
306
307 return nb_cli_apply_changes(vty, NULL);
308}
309
ca77b518 310DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 328DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 349DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 368DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 388DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 403DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 421DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 437DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 456DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 474DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 493DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 508DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 525DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 540DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 557DEFPY_YANG(
2b3e4807
RZ
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
572void 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");
2b3e4807
RZ
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 */
2b3e4807
RZ
584 switch (condition) {
585 case 1:
375d157f
RZ
586 vty_out(vty, " match ip address %s\n",
587 yang_dnode_get_string(dnode, "./list-name"));
2b3e4807
RZ
588 break;
589 case 3:
375d157f
RZ
590 vty_out(vty, " match ip next-hop %s\n",
591 yang_dnode_get_string(dnode, "./list-name"));
2b3e4807
RZ
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;
f42cc965
RZ
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"));
2b3e4807
RZ
646 break;
647 }
648}
649
ca77b518 650DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 668DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 684DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 703DEFPY_YANG(
2b3e4807
RZ
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
ca77b518 720DEFPY_YANG(
2b3e4807
RZ
721 set_metric, set_metric_cmd,
722 "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
723 SET_STR
724 "Metric value for destination routing protocol\n"
725 "Metric value\n"
726 "Assign round trip time\n"
727 "Add round trip time\n"
728 "Subtract round trip time\n"
729 "Add metric\n"
730 "Subtract metric\n")
731{
732 const char *xpath = "./set-action[action='metric']";
733 char xpath_value[XPATH_MAXLEN];
734 char value[64];
735
736 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
737 if (rtt) {
738 snprintf(xpath_value, sizeof(xpath_value),
739 "%s/use-round-trip-time", xpath);
740 snprintf(value, sizeof(value), "true");
741 } else if (artt) {
742 snprintf(xpath_value, sizeof(xpath_value),
743 "%s/add-round-trip-time", xpath);
744 snprintf(value, sizeof(value), "true");
745 } else if (srtt) {
746 snprintf(xpath_value, sizeof(xpath_value),
747 "%s/subtract-round-trip-time", xpath);
748 snprintf(value, sizeof(value), "true");
749 } else if (ametric) {
750 snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric",
751 xpath);
752 snprintf(value, sizeof(value), "true");
753 } else if (smetric) {
754 snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric",
755 xpath);
756 snprintf(value, sizeof(value), "true");
757 } else {
758 snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath);
759 snprintf(value, sizeof(value), "%lu", metric);
760 }
761 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value);
762
763 return nb_cli_apply_changes(vty, NULL);
764}
765
ca77b518 766DEFPY_YANG(
2b3e4807
RZ
767 no_set_metric, no_set_metric_cmd,
768 "no set metric [(0-4294967295)]",
769 NO_STR
770 SET_STR
771 "Metric value for destination routing protocol\n"
772 "Metric value\n")
773{
774 const char *xpath = "./set-action[action='metric']";
775
776 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
777 return nb_cli_apply_changes(vty, NULL);
778}
779
ca77b518 780DEFPY_YANG(
2b3e4807
RZ
781 set_tag, set_tag_cmd,
782 "set tag (1-4294967295)$tag",
783 SET_STR
784 "Tag value for routing protocol\n"
785 "Tag value\n")
786{
787 const char *xpath = "./set-action[action='tag']";
788 char xpath_value[XPATH_MAXLEN];
789
790 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
791 snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
792 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
793
794 return nb_cli_apply_changes(vty, NULL);
795}
796
ca77b518 797DEFPY_YANG(
2b3e4807
RZ
798 no_set_tag, no_set_tag_cmd,
799 "no set tag [(1-4294967295)]",
800 NO_STR
801 SET_STR
802 "Tag value for routing protocol\n"
803 "Tag value\n")
804{
805 const char *xpath = "./set-action[action='tag']";
806
807 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
808
809 return nb_cli_apply_changes(vty, NULL);
810}
811
812void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
813 bool show_defaults)
814{
815 int action = yang_dnode_get_enum(dnode, "./action");
816
817 switch (action) {
818 case 0: /* ipv4-next-hop */
819 vty_out(vty, " set ip next-hop %s\n",
820 yang_dnode_get_string(dnode, "./ipv4-address"));
821 break;
822 case 1: /* ipv6-next-hop */
823 vty_out(vty, " set ipv6 next-hop local %s\n",
824 yang_dnode_get_string(dnode, "./ipv6-address"));
825 break;
826 case 2: /* metric */
827 if (yang_dnode_get(dnode, "./use-round-trip-time")) {
828 vty_out(vty, " set metric rtt\n");
829 } else if (yang_dnode_get(dnode, "./add-round-trip-time")) {
830 vty_out(vty, " set metric +rtt\n");
831 } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) {
832 vty_out(vty, " set metric -rtt\n");
833 } else if (yang_dnode_get(dnode, "./add-metric")) {
834 vty_out(vty, " set metric +metric\n");
835 } else if (yang_dnode_get(dnode, "./subtract-metric")) {
836 vty_out(vty, " set metric -metric\n");
837 } else {
838 vty_out(vty, " set metric %s\n",
839 yang_dnode_get_string(dnode, "./value"));
840 }
841 break;
842 case 3: /* tag */
843 vty_out(vty, " set tag %s\n",
844 yang_dnode_get_string(dnode, "./tag"));
845 break;
f42cc965
RZ
846 case 100: /* source */
847 if (yang_dnode_exists(dnode, "./frr-zebra:source-v4"))
848 vty_out(vty, " set src %s\n",
849 yang_dnode_get_string(dnode, "./frr-zebra:source-v4"));
850 else
851 vty_out(vty, " set src %s\n",
852 yang_dnode_get_string(dnode, "./frr-zebra:source-v6"));
2b3e4807
RZ
853 break;
854 }
855}
856
ca77b518 857DEFPY_YANG(
2b3e4807
RZ
858 rmap_onmatch_next, rmap_onmatch_next_cmd,
859 "on-match next",
860 "Exit policy on matches\n"
861 "Next clause\n")
862{
863 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next");
864
865 return nb_cli_apply_changes(vty, NULL);
866}
867
ca77b518 868DEFPY_YANG(
2b3e4807
RZ
869 no_rmap_onmatch_next,
870 no_rmap_onmatch_next_cmd,
871 "no on-match next",
872 NO_STR
873 "Exit policy on matches\n"
874 "Next clause\n")
875{
876 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
877
878 return nb_cli_apply_changes(vty, NULL);
879}
880
ca77b518 881DEFPY_YANG(
2b3e4807
RZ
882 rmap_onmatch_goto, rmap_onmatch_goto_cmd,
883 "on-match goto (1-65535)$rm_num",
884 "Exit policy on matches\n"
885 "Goto Clause number\n"
886 "Number\n")
887{
888 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto");
889 nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str);
890
891 return nb_cli_apply_changes(vty, NULL);
892}
893
ca77b518 894DEFPY_YANG(
2b3e4807
RZ
895 no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd,
896 "no on-match goto",
897 NO_STR
898 "Exit policy on matches\n"
899 "Goto Clause number\n")
900{
901 nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
902
903 return nb_cli_apply_changes(vty, NULL);
904}
905
906/* Cisco/GNU Zebra compatibility aliases */
ca77b518 907ALIAS_YANG(
2b3e4807
RZ
908 rmap_onmatch_goto, rmap_continue_cmd,
909 "continue (1-65535)$rm_num",
910 "Continue on a different entry within the route-map\n"
911 "Route-map entry sequence number\n")
912
ca77b518 913ALIAS_YANG(
2b3e4807
RZ
914 no_rmap_onmatch_goto, no_rmap_continue_cmd,
915 "no continue [(1-65535)]",
916 NO_STR
917 "Continue on a different entry within the route-map\n"
918 "Route-map entry sequence number\n")
919
920void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
921 bool show_defaults)
922{
923 int exit_policy = yang_dnode_get_enum(dnode, NULL);
924
925 switch (exit_policy) {
926 case 0: /* permit-or-deny */
927 /* NOTHING: default option. */
928 break;
929 case 1: /* next */
930 vty_out(vty, " on-match next\n");
931 break;
932 case 2: /* goto */
933 vty_out(vty, " on-match goto %s\n",
934 yang_dnode_get_string(dnode, "../goto-value"));
935 break;
936 }
937}
938
ca77b518 939DEFPY_YANG(
2b3e4807
RZ
940 rmap_call, rmap_call_cmd,
941 "call WORD$name",
942 "Jump to another Route-Map after match+set\n"
943 "Target route-map name\n")
944{
945 nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name);
946
947 return nb_cli_apply_changes(vty, NULL);
948}
949
ca77b518 950DEFPY_YANG(
2b3e4807 951 no_rmap_call, no_rmap_call_cmd,
680b9b62 952 "no call [NAME]",
2b3e4807
RZ
953 NO_STR
954 "Jump to another Route-Map after match+set\n")
955{
956 nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL);
957
958 return nb_cli_apply_changes(vty, NULL);
959}
960
961void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
962 bool show_defaults)
963{
964 vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
965}
966
ca77b518 967DEFPY_YANG(
2b3e4807
RZ
968 rmap_description, rmap_description_cmd,
969 "description LINE...",
970 "Route-map comment\n"
971 "Comment describing this route-map rule\n")
972{
973 char *desc;
974 int rv;
975
976 desc = argv_concat(argv, argc, 1);
977 nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
978 rv = nb_cli_apply_changes(vty, NULL);
979 XFREE(MTYPE_TMP, desc);
980
981 return rv;
982}
983
ca77b518 984DEFUN_YANG (no_rmap_description,
2b3e4807
RZ
985 no_rmap_description_cmd,
986 "no description",
987 NO_STR
988 "Route-map comment\n")
989{
990 nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
991
992 return nb_cli_apply_changes(vty, NULL);
993}
994
995void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
996 bool show_defaults)
997{
998 vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
999}
1000
1001static int route_map_config_write(struct vty *vty)
1002{
1003 struct lyd_node *dnode;
1004 int written = 0;
1005
1006 dnode = yang_dnode_get(running_config->dnode,
1007 "/frr-route-map:lib");
1008 if (dnode) {
1009 nb_cli_show_dnode_cmds(vty, dnode, false);
1010 written = 1;
1011 }
1012
1013 return written;
1014}
1015
1016/* Route map node structure. */
612c2c15 1017static int route_map_config_write(struct vty *vty);
62b346ee 1018static struct cmd_node rmap_node = {
f4b8291f 1019 .name = "routemap",
62b346ee 1020 .node = RMAP_NODE,
24389580 1021 .parent_node = CONFIG_NODE,
62b346ee 1022 .prompt = "%s(config-route-map)# ",
612c2c15 1023 .config_write = route_map_config_write,
62b346ee 1024};
2b3e4807
RZ
1025
1026static void rmap_autocomplete(vector comps, struct cmd_token *token)
1027{
1028 struct route_map *map;
1029
1030 for (map = route_map_master.head; map; map = map->next)
1031 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
1032}
1033
1034static const struct cmd_variable_handler rmap_var_handlers[] = {
1035 {.varname = "route_map", .completions = rmap_autocomplete},
1036 {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
1037 {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
1038 {.completions = NULL}
1039};
1040
1041void route_map_cli_init(void)
1042{
1043 /* Auto complete handler. */
1044 cmd_variable_handler_register(rmap_var_handlers);
1045
1046 /* CLI commands. */
612c2c15 1047 install_node(&rmap_node);
2b3e4807
RZ
1048 install_default(RMAP_NODE);
1049 install_element(CONFIG_NODE, &route_map_cmd);
1050 install_element(CONFIG_NODE, &no_route_map_cmd);
1051 install_element(CONFIG_NODE, &no_route_map_all_cmd);
1052
1053 /* Install the on-match stuff */
2b3e4807
RZ
1054 install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
1055 install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
1056 install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
1057 install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
1058 install_element(RMAP_NODE, &rmap_continue_cmd);
1059 install_element(RMAP_NODE, &no_rmap_continue_cmd);
1060
1061 /* Install the call stuff. */
1062 install_element(RMAP_NODE, &rmap_call_cmd);
1063 install_element(RMAP_NODE, &no_rmap_call_cmd);
1064
1065 /* Install description commands. */
1066 install_element(RMAP_NODE, &rmap_description_cmd);
1067 install_element(RMAP_NODE, &no_rmap_description_cmd);
1068
1069 /* Install 'match' commands. */
1070 install_element(RMAP_NODE, &match_interface_cmd);
1071 install_element(RMAP_NODE, &no_match_interface_cmd);
1072
1073 install_element(RMAP_NODE, &match_ip_address_cmd);
1074 install_element(RMAP_NODE, &no_match_ip_address_cmd);
1075
1076 install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
1077 install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
1078
1079 install_element(RMAP_NODE, &match_ip_next_hop_cmd);
1080 install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
1081
1082 install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
1083 install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
1084
1085 install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
1086 install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
1087
1088 install_element(RMAP_NODE, &match_ipv6_address_cmd);
1089 install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
1090
1091 install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
1092 install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
1093
1094 install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
1095 install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
1096
1097 install_element(RMAP_NODE, &match_metric_cmd);
1098 install_element(RMAP_NODE, &no_match_metric_cmd);
1099
1100 install_element(RMAP_NODE, &match_tag_cmd);
1101 install_element(RMAP_NODE, &no_match_tag_cmd);
1102
1103 /* Install 'set' commands. */
1104 install_element(RMAP_NODE, &set_ip_nexthop_cmd);
1105 install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
1106
1107 install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
1108 install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
1109
1110 install_element(RMAP_NODE, &set_metric_cmd);
1111 install_element(RMAP_NODE, &no_set_metric_cmd);
1112
1113 install_element(RMAP_NODE, &set_tag_cmd);
1114 install_element(RMAP_NODE, &no_set_tag_cmd);
1115}