]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1998 Kunihiro Ishiguro | |
3 | * Copyright (C) 2018 NetDEF, Inc. | |
4 | * Renato Westphal | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the Free | |
8 | * Software Foundation; either version 2 of the License, or (at your option) | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along | |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "if.h" | |
24 | #include "vrf.h" | |
25 | #include "log.h" | |
26 | #include "prefix.h" | |
27 | #include "command.h" | |
28 | #include "northbound_cli.h" | |
29 | #include "libfrr.h" | |
30 | ||
31 | #include "ripngd/ripngd.h" | |
32 | #include "ripngd/ripng_nb.h" | |
33 | #ifndef VTYSH_EXTRACT_PL | |
34 | #include "ripngd/ripng_cli_clippy.c" | |
35 | #endif | |
36 | ||
37 | /* | |
38 | * XPath: /frr-ripngd:ripngd/instance | |
39 | */ | |
40 | DEFPY_NOSH (router_ripng, | |
41 | router_ripng_cmd, | |
42 | "router ripng [vrf NAME]", | |
43 | "Enable a routing process\n" | |
44 | "Make RIPng instance command\n" | |
45 | VRF_CMD_HELP_STR) | |
46 | { | |
47 | char xpath[XPATH_MAXLEN]; | |
48 | int ret; | |
49 | ||
50 | /* Build RIPng instance XPath. */ | |
51 | if (!vrf) | |
52 | vrf = VRF_DEFAULT_NAME; | |
53 | snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", | |
54 | vrf); | |
55 | ||
56 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
57 | ||
58 | ret = nb_cli_apply_changes(vty, NULL); | |
59 | if (ret == CMD_SUCCESS) | |
60 | VTY_PUSH_XPATH(RIPNG_NODE, xpath); | |
61 | ||
62 | return ret; | |
63 | } | |
64 | ||
65 | DEFPY (no_router_ripng, | |
66 | no_router_ripng_cmd, | |
67 | "no router ripng [vrf NAME]", | |
68 | NO_STR | |
69 | "Enable a routing process\n" | |
70 | "Make RIPng instance command\n" | |
71 | VRF_CMD_HELP_STR) | |
72 | { | |
73 | char xpath[XPATH_MAXLEN]; | |
74 | ||
75 | /* Build RIPng instance XPath. */ | |
76 | if (!vrf) | |
77 | vrf = VRF_DEFAULT_NAME; | |
78 | snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", | |
79 | vrf); | |
80 | ||
81 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
82 | ||
83 | return nb_cli_apply_changes(vty, NULL); | |
84 | } | |
85 | ||
86 | void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode, | |
87 | bool show_defaults) | |
88 | { | |
89 | const char *vrf_name; | |
90 | ||
91 | vrf_name = yang_dnode_get_string(dnode, "./vrf"); | |
92 | ||
93 | vty_out(vty, "!\n"); | |
94 | vty_out(vty, "router ripng"); | |
95 | if (!strmatch(vrf_name, VRF_DEFAULT_NAME)) | |
96 | vty_out(vty, " vrf %s", vrf_name); | |
97 | vty_out(vty, "\n"); | |
98 | } | |
99 | ||
100 | /* | |
101 | * XPath: /frr-ripngd:ripngd/instance/allow-ecmp | |
102 | */ | |
103 | DEFPY (ripng_allow_ecmp, | |
104 | ripng_allow_ecmp_cmd, | |
105 | "[no] allow-ecmp", | |
106 | NO_STR | |
107 | "Allow Equal Cost MultiPath\n") | |
108 | { | |
109 | nb_cli_enqueue_change(vty, "./allow-ecmp", NB_OP_MODIFY, | |
110 | no ? "false" : "true"); | |
111 | ||
112 | return nb_cli_apply_changes(vty, NULL); | |
113 | } | |
114 | ||
115 | void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode, | |
116 | bool show_defaults) | |
117 | { | |
118 | if (!yang_dnode_get_bool(dnode, NULL)) | |
119 | vty_out(vty, " no"); | |
120 | ||
121 | vty_out(vty, " allow-ecmp\n"); | |
122 | } | |
123 | ||
124 | /* | |
125 | * XPath: /frr-ripngd:ripngd/instance/default-information-originate | |
126 | */ | |
127 | DEFPY (ripng_default_information_originate, | |
128 | ripng_default_information_originate_cmd, | |
129 | "[no] default-information originate", | |
130 | NO_STR | |
131 | "Default route information\n" | |
132 | "Distribute default route\n") | |
133 | { | |
134 | nb_cli_enqueue_change(vty, "./default-information-originate", | |
135 | NB_OP_MODIFY, no ? "false" : "true"); | |
136 | ||
137 | return nb_cli_apply_changes(vty, NULL); | |
138 | } | |
139 | ||
140 | void cli_show_ripng_default_information_originate(struct vty *vty, | |
141 | struct lyd_node *dnode, | |
142 | bool show_defaults) | |
143 | { | |
144 | if (!yang_dnode_get_bool(dnode, NULL)) | |
145 | vty_out(vty, " no"); | |
146 | ||
147 | vty_out(vty, " default-information originate\n"); | |
148 | } | |
149 | ||
150 | /* | |
151 | * XPath: /frr-ripngd:ripngd/instance/default-metric | |
152 | */ | |
153 | DEFPY (ripng_default_metric, | |
154 | ripng_default_metric_cmd, | |
155 | "default-metric (1-16)", | |
156 | "Set a metric of redistribute routes\n" | |
157 | "Default metric\n") | |
158 | { | |
159 | nb_cli_enqueue_change(vty, "./default-metric", NB_OP_MODIFY, | |
160 | default_metric_str); | |
161 | ||
162 | return nb_cli_apply_changes(vty, NULL); | |
163 | } | |
164 | ||
165 | DEFPY (no_ripng_default_metric, | |
166 | no_ripng_default_metric_cmd, | |
167 | "no default-metric [(1-16)]", | |
168 | NO_STR | |
169 | "Set a metric of redistribute routes\n" | |
170 | "Default metric\n") | |
171 | { | |
172 | nb_cli_enqueue_change(vty, "./default-metric", NB_OP_MODIFY, NULL); | |
173 | ||
174 | return nb_cli_apply_changes(vty, NULL); | |
175 | } | |
176 | ||
177 | void cli_show_ripng_default_metric(struct vty *vty, struct lyd_node *dnode, | |
178 | bool show_defaults) | |
179 | { | |
180 | vty_out(vty, " default-metric %s\n", | |
181 | yang_dnode_get_string(dnode, NULL)); | |
182 | } | |
183 | ||
184 | /* | |
185 | * XPath: /frr-ripngd:ripngd/instance/network | |
186 | */ | |
187 | DEFPY (ripng_network_prefix, | |
188 | ripng_network_prefix_cmd, | |
189 | "[no] network X:X::X:X/M", | |
190 | NO_STR | |
191 | "RIPng enable on specified interface or network.\n" | |
192 | "IPv6 network\n") | |
193 | { | |
194 | nb_cli_enqueue_change(vty, "./network", | |
195 | no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); | |
196 | ||
197 | return nb_cli_apply_changes(vty, NULL); | |
198 | } | |
199 | ||
200 | void cli_show_ripng_network_prefix(struct vty *vty, struct lyd_node *dnode, | |
201 | bool show_defaults) | |
202 | { | |
203 | vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); | |
204 | } | |
205 | ||
206 | /* | |
207 | * XPath: /frr-ripngd:ripngd/instance/interface | |
208 | */ | |
209 | DEFPY (ripng_network_if, | |
210 | ripng_network_if_cmd, | |
211 | "[no] network WORD", | |
212 | NO_STR | |
213 | "RIPng enable on specified interface or network.\n" | |
214 | "Interface name\n") | |
215 | { | |
216 | nb_cli_enqueue_change(vty, "./interface", | |
217 | no ? NB_OP_DESTROY : NB_OP_CREATE, network); | |
218 | ||
219 | return nb_cli_apply_changes(vty, NULL); | |
220 | } | |
221 | ||
222 | void cli_show_ripng_network_interface(struct vty *vty, struct lyd_node *dnode, | |
223 | bool show_defaults) | |
224 | { | |
225 | vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); | |
226 | } | |
227 | ||
228 | /* | |
229 | * XPath: /frr-ripngd:ripngd/instance/offset-list | |
230 | */ | |
231 | DEFPY (ripng_offset_list, | |
232 | ripng_offset_list_cmd, | |
233 | "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]", | |
234 | NO_STR | |
235 | "Modify RIPng metric\n" | |
236 | "Access-list name\n" | |
237 | "For incoming updates\n" | |
238 | "For outgoing updates\n" | |
239 | "Metric value\n" | |
240 | "Interface to match\n") | |
241 | { | |
242 | if (!no) { | |
243 | nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); | |
244 | nb_cli_enqueue_change(vty, "./access-list", NB_OP_MODIFY, acl); | |
245 | nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, | |
246 | metric_str); | |
247 | } else | |
248 | nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); | |
249 | ||
250 | return nb_cli_apply_changes( | |
251 | vty, "./offset-list[interface='%s'][direction='%s']", | |
252 | ifname ? ifname : "*", direction); | |
253 | } | |
254 | ||
255 | void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode, | |
256 | bool show_defaults) | |
257 | { | |
258 | const char *interface; | |
259 | ||
260 | interface = yang_dnode_get_string(dnode, "./interface"); | |
261 | ||
262 | vty_out(vty, " offset-list %s %s %s", | |
263 | yang_dnode_get_string(dnode, "./access-list"), | |
264 | yang_dnode_get_string(dnode, "./direction"), | |
265 | yang_dnode_get_string(dnode, "./metric")); | |
266 | if (!strmatch(interface, "*")) | |
267 | vty_out(vty, " %s", interface); | |
268 | vty_out(vty, "\n"); | |
269 | } | |
270 | ||
271 | /* | |
272 | * XPath: /frr-ripngd:ripngd/instance/passive-interface | |
273 | */ | |
274 | DEFPY (ripng_passive_interface, | |
275 | ripng_passive_interface_cmd, | |
276 | "[no] passive-interface IFNAME", | |
277 | NO_STR | |
278 | "Suppress routing updates on an interface\n" | |
279 | "Interface name\n") | |
280 | { | |
281 | nb_cli_enqueue_change(vty, "./passive-interface", | |
282 | no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); | |
283 | ||
284 | return nb_cli_apply_changes(vty, NULL); | |
285 | } | |
286 | ||
287 | void cli_show_ripng_passive_interface(struct vty *vty, struct lyd_node *dnode, | |
288 | bool show_defaults) | |
289 | { | |
290 | vty_out(vty, " passive-interface %s\n", | |
291 | yang_dnode_get_string(dnode, NULL)); | |
292 | } | |
293 | ||
294 | /* | |
295 | * XPath: /frr-ripngd:ripngd/instance/redistribute | |
296 | */ | |
297 | DEFPY (ripng_redistribute, | |
298 | ripng_redistribute_cmd, | |
299 | "[no] redistribute " FRR_REDIST_STR_RIPNGD "$protocol [{metric (0-16)|route-map WORD}]", | |
300 | NO_STR | |
301 | REDIST_STR | |
302 | FRR_REDIST_HELP_STR_RIPNGD | |
303 | "Metric\n" | |
304 | "Metric value\n" | |
305 | "Route map reference\n" | |
306 | "Pointer to route-map entries\n") | |
307 | { | |
308 | if (!no) { | |
309 | nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); | |
310 | nb_cli_enqueue_change(vty, "./route-map", | |
311 | route_map ? NB_OP_MODIFY : NB_OP_DESTROY, | |
312 | route_map); | |
313 | nb_cli_enqueue_change(vty, "./metric", | |
314 | metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, | |
315 | metric_str); | |
316 | } else | |
317 | nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); | |
318 | ||
319 | return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", | |
320 | protocol); | |
321 | } | |
322 | ||
323 | void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode, | |
324 | bool show_defaults) | |
325 | { | |
326 | vty_out(vty, " redistribute %s", | |
327 | yang_dnode_get_string(dnode, "./protocol")); | |
328 | if (yang_dnode_exists(dnode, "./metric")) | |
329 | vty_out(vty, " metric %s", | |
330 | yang_dnode_get_string(dnode, "./metric")); | |
331 | if (yang_dnode_exists(dnode, "./route-map")) | |
332 | vty_out(vty, " route-map %s", | |
333 | yang_dnode_get_string(dnode, "./route-map")); | |
334 | vty_out(vty, "\n"); | |
335 | } | |
336 | ||
337 | /* | |
338 | * XPath: /frr-ripngd:ripngd/instance/static-route | |
339 | */ | |
340 | DEFPY (ripng_route, | |
341 | ripng_route_cmd, | |
342 | "[no] route X:X::X:X/M", | |
343 | NO_STR | |
344 | "Static route setup\n" | |
345 | "Set static RIPng route announcement\n") | |
346 | { | |
347 | nb_cli_enqueue_change(vty, "./static-route", | |
348 | no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); | |
349 | ||
350 | return nb_cli_apply_changes(vty, NULL); | |
351 | } | |
352 | ||
353 | void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode, | |
354 | bool show_defaults) | |
355 | { | |
356 | vty_out(vty, " route %s\n", yang_dnode_get_string(dnode, NULL)); | |
357 | } | |
358 | ||
359 | /* | |
360 | * XPath: /frr-ripngd:ripngd/instance/aggregate-addres | |
361 | */ | |
362 | DEFPY (ripng_aggregate_address, | |
363 | ripng_aggregate_address_cmd, | |
364 | "[no] aggregate-address X:X::X:X/M", | |
365 | NO_STR | |
366 | "Set aggregate RIPng route announcement\n" | |
367 | "Aggregate network\n") | |
368 | { | |
369 | nb_cli_enqueue_change(vty, "./aggregate-address", | |
370 | no ? NB_OP_DESTROY : NB_OP_CREATE, | |
371 | aggregate_address_str); | |
372 | ||
373 | return nb_cli_apply_changes(vty, NULL); | |
374 | } | |
375 | ||
376 | void cli_show_ripng_aggregate_address(struct vty *vty, struct lyd_node *dnode, | |
377 | bool show_defaults) | |
378 | { | |
379 | vty_out(vty, " aggregate-address %s\n", | |
380 | yang_dnode_get_string(dnode, NULL)); | |
381 | } | |
382 | ||
383 | /* | |
384 | * XPath: /frr-ripngd:ripngd/instance/timers | |
385 | */ | |
386 | DEFPY (ripng_timers, | |
387 | ripng_timers_cmd, | |
388 | "timers basic (1-65535)$update (1-65535)$timeout (1-65535)$garbage", | |
389 | "RIPng timers setup\n" | |
390 | "Basic timer\n" | |
391 | "Routing table update timer value in second. Default is 30.\n" | |
392 | "Routing information timeout timer. Default is 180.\n" | |
393 | "Garbage collection timer. Default is 120.\n") | |
394 | { | |
395 | nb_cli_enqueue_change(vty, "./update-interval", NB_OP_MODIFY, | |
396 | update_str); | |
397 | nb_cli_enqueue_change(vty, "./holddown-interval", NB_OP_MODIFY, | |
398 | timeout_str); | |
399 | nb_cli_enqueue_change(vty, "./flush-interval", NB_OP_MODIFY, | |
400 | garbage_str); | |
401 | ||
402 | return nb_cli_apply_changes(vty, "./timers"); | |
403 | } | |
404 | ||
405 | DEFPY (no_ripng_timers, | |
406 | no_ripng_timers_cmd, | |
407 | "no timers basic [(1-65535) (1-65535) (1-65535)]", | |
408 | NO_STR | |
409 | "RIPng timers setup\n" | |
410 | "Basic timer\n" | |
411 | "Routing table update timer value in second. Default is 30.\n" | |
412 | "Routing information timeout timer. Default is 180.\n" | |
413 | "Garbage collection timer. Default is 120.\n") | |
414 | { | |
415 | nb_cli_enqueue_change(vty, "./update-interval", NB_OP_MODIFY, NULL); | |
416 | nb_cli_enqueue_change(vty, "./holddown-interval", NB_OP_MODIFY, NULL); | |
417 | nb_cli_enqueue_change(vty, "./flush-interval", NB_OP_MODIFY, NULL); | |
418 | ||
419 | return nb_cli_apply_changes(vty, "./timers"); | |
420 | } | |
421 | ||
422 | void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode, | |
423 | bool show_defaults) | |
424 | { | |
425 | vty_out(vty, " timers basic %s %s %s\n", | |
426 | yang_dnode_get_string(dnode, "./update-interval"), | |
427 | yang_dnode_get_string(dnode, "./holddown-interval"), | |
428 | yang_dnode_get_string(dnode, "./flush-interval")); | |
429 | } | |
430 | ||
431 | /* | |
432 | * XPath: /frr-interface:lib/interface/frr-ripngd:ripng/split-horizon | |
433 | */ | |
434 | DEFPY (ipv6_ripng_split_horizon, | |
435 | ipv6_ripng_split_horizon_cmd, | |
436 | "[no] ipv6 ripng split-horizon [poisoned-reverse$poisoned_reverse]", | |
437 | NO_STR | |
438 | IPV6_STR | |
439 | "Routing Information Protocol\n" | |
440 | "Perform split horizon\n" | |
441 | "With poisoned-reverse\n") | |
442 | { | |
443 | const char *value; | |
444 | ||
445 | if (no) | |
446 | value = "disabled"; | |
447 | else if (poisoned_reverse) | |
448 | value = "poison-reverse"; | |
449 | else | |
450 | value = "simple"; | |
451 | ||
452 | nb_cli_enqueue_change(vty, "./split-horizon", NB_OP_MODIFY, value); | |
453 | ||
454 | return nb_cli_apply_changes(vty, "./frr-ripngd:ripng"); | |
455 | } | |
456 | ||
457 | void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode, | |
458 | bool show_defaults) | |
459 | { | |
460 | int value; | |
461 | ||
462 | value = yang_dnode_get_enum(dnode, NULL); | |
463 | switch (value) { | |
464 | case RIPNG_NO_SPLIT_HORIZON: | |
465 | vty_out(vty, " no ipv6 ripng split-horizon\n"); | |
466 | break; | |
467 | case RIPNG_SPLIT_HORIZON: | |
468 | vty_out(vty, " ipv6 ripng split-horizon\n"); | |
469 | break; | |
470 | case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: | |
471 | vty_out(vty, " ipv6 ripng split-horizon poisoned-reverse\n"); | |
472 | break; | |
473 | } | |
474 | } | |
475 | ||
476 | /* | |
477 | * XPath: /frr-ripngd:clear-ripng-route | |
478 | */ | |
479 | DEFPY (clear_ipv6_rip, | |
480 | clear_ipv6_rip_cmd, | |
481 | "clear ipv6 ripng [vrf WORD]", | |
482 | CLEAR_STR | |
483 | IPV6_STR | |
484 | "Clear IPv6 RIP database\n" | |
485 | VRF_CMD_HELP_STR) | |
486 | { | |
487 | struct list *input; | |
488 | ||
489 | input = list_new(); | |
490 | if (vrf) { | |
491 | struct yang_data *yang_vrf; | |
492 | ||
493 | yang_vrf = yang_data_new( | |
494 | "/frr-ripngd:clear-ripng-route/input/vrf", vrf); | |
495 | listnode_add(input, yang_vrf); | |
496 | } | |
497 | ||
498 | return nb_cli_rpc("/frr-ripngd:clear-ripng-route", input, NULL); | |
499 | } | |
500 | ||
501 | void ripng_cli_init(void) | |
502 | { | |
503 | install_element(CONFIG_NODE, &router_ripng_cmd); | |
504 | install_element(CONFIG_NODE, &no_router_ripng_cmd); | |
505 | ||
506 | install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd); | |
507 | install_element(RIPNG_NODE, &ripng_default_information_originate_cmd); | |
508 | install_element(RIPNG_NODE, &ripng_default_metric_cmd); | |
509 | install_element(RIPNG_NODE, &no_ripng_default_metric_cmd); | |
510 | install_element(RIPNG_NODE, &ripng_network_prefix_cmd); | |
511 | install_element(RIPNG_NODE, &ripng_network_if_cmd); | |
512 | install_element(RIPNG_NODE, &ripng_offset_list_cmd); | |
513 | install_element(RIPNG_NODE, &ripng_passive_interface_cmd); | |
514 | install_element(RIPNG_NODE, &ripng_redistribute_cmd); | |
515 | install_element(RIPNG_NODE, &ripng_route_cmd); | |
516 | install_element(RIPNG_NODE, &ripng_aggregate_address_cmd); | |
517 | install_element(RIPNG_NODE, &ripng_timers_cmd); | |
518 | install_element(RIPNG_NODE, &no_ripng_timers_cmd); | |
519 | ||
520 | install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); | |
521 | ||
522 | install_element(ENABLE_NODE, &clear_ipv6_rip_cmd); | |
523 | } |