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_YANG_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_YANG (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 
cli_show_router_ripng(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_allow_ecmp(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_default_information_originate(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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_YANG (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 
cli_show_ripng_default_metric(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_network_prefix(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_network_interface(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_offset_list(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_passive_interface(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_redistribute(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_route(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ripng_aggregate_address(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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_YANG (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 
cli_show_ripng_timers(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 
cli_show_ipv6_ripng_split_horizon(struct vty * vty,struct lyd_node * dnode,bool show_defaults)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_YANG (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 	int ret;
489 
490 	input = list_new();
491 	if (vrf) {
492 		struct yang_data *yang_vrf;
493 
494 		yang_vrf = yang_data_new(
495 			"/frr-ripngd:clear-ripng-route/input/vrf", vrf);
496 		listnode_add(input, yang_vrf);
497 	}
498 
499 	ret = nb_cli_rpc("/frr-ripngd:clear-ripng-route", input, NULL);
500 
501 	list_delete(&input);
502 
503 	return ret;
504 }
505 
ripng_cli_init(void)506 void ripng_cli_init(void)
507 {
508 	install_element(CONFIG_NODE, &router_ripng_cmd);
509 	install_element(CONFIG_NODE, &no_router_ripng_cmd);
510 
511 	install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd);
512 	install_element(RIPNG_NODE, &ripng_default_information_originate_cmd);
513 	install_element(RIPNG_NODE, &ripng_default_metric_cmd);
514 	install_element(RIPNG_NODE, &no_ripng_default_metric_cmd);
515 	install_element(RIPNG_NODE, &ripng_network_prefix_cmd);
516 	install_element(RIPNG_NODE, &ripng_network_if_cmd);
517 	install_element(RIPNG_NODE, &ripng_offset_list_cmd);
518 	install_element(RIPNG_NODE, &ripng_passive_interface_cmd);
519 	install_element(RIPNG_NODE, &ripng_redistribute_cmd);
520 	install_element(RIPNG_NODE, &ripng_route_cmd);
521 	install_element(RIPNG_NODE, &ripng_aggregate_address_cmd);
522 	install_element(RIPNG_NODE, &ripng_timers_cmd);
523 	install_element(RIPNG_NODE, &no_ripng_timers_cmd);
524 
525 	install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
526 
527 	install_element(ENABLE_NODE, &clear_ipv6_rip_cmd);
528 }
529