1 /*
2  * Interface related function for RIPng.
3  * Copyright (C) 1998 Kunihiro Ishiguro
4  *
5  * This file is part of GNU Zebra.
6  *
7  * GNU Zebra is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2, or (at your option) any
10  * later version.
11  *
12  * GNU Zebra is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; see the file COPYING; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <zebra.h>
23 
24 #include "linklist.h"
25 #include "if.h"
26 #include "prefix.h"
27 #include "memory.h"
28 #include "network.h"
29 #include "filter.h"
30 #include "log.h"
31 #include "stream.h"
32 #include "zclient.h"
33 #include "command.h"
34 #include "agg_table.h"
35 #include "thread.h"
36 #include "privs.h"
37 #include "vrf.h"
38 #include "lib_errors.h"
39 #include "northbound_cli.h"
40 
41 #include "ripngd/ripngd.h"
42 #include "ripngd/ripng_debug.h"
43 
44 /* If RFC2133 definition is used. */
45 #ifndef IPV6_JOIN_GROUP
46 #define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP
47 #endif
48 #ifndef IPV6_LEAVE_GROUP
49 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
50 #endif
51 
52 DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface")
53 
54 /* Static utility function. */
55 static void ripng_enable_apply(struct interface *);
56 static void ripng_passive_interface_apply(struct interface *);
57 static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname);
58 static int ripng_enable_network_lookup2(struct connected *);
59 static void ripng_enable_apply_all(struct ripng *ripng);
60 
61 /* Join to the all rip routers multicast group. */
ripng_multicast_join(struct interface * ifp,int sock)62 static int ripng_multicast_join(struct interface *ifp, int sock)
63 {
64 	int ret;
65 	struct ipv6_mreq mreq;
66 	int save_errno;
67 
68 	if (if_is_multicast(ifp)) {
69 		memset(&mreq, 0, sizeof(mreq));
70 		inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
71 		mreq.ipv6mr_interface = ifp->ifindex;
72 
73 		/*
74 		 * NetBSD 1.6.2 requires root to join groups on gif(4).
75 		 * While this is bogus, privs are available and easy to use
76 		 * for this call as a workaround.
77 		 */
78 		frr_with_privs(&ripngd_privs) {
79 
80 			ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
81 					 (char *)&mreq, sizeof(mreq));
82 			save_errno = errno;
83 
84 		}
85 
86 		if (ret < 0 && save_errno == EADDRINUSE) {
87 			/*
88 			 * Group is already joined.  This occurs due to sloppy
89 			 * group
90 			 * management, in particular declining to leave the
91 			 * group on
92 			 * an interface that has just gone down.
93 			 */
94 			zlog_warn("ripng join on %s EADDRINUSE (ignoring)",
95 				  ifp->name);
96 			return 0; /* not an error */
97 		}
98 
99 		if (ret < 0)
100 			zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s",
101 				  safe_strerror(save_errno));
102 
103 		if (IS_RIPNG_DEBUG_EVENT)
104 			zlog_debug(
105 				"RIPng %s join to all-rip-routers multicast group",
106 				ifp->name);
107 
108 		if (ret < 0)
109 			return -1;
110 	}
111 	return 0;
112 }
113 
114 /* Leave from the all rip routers multicast group. */
ripng_multicast_leave(struct interface * ifp,int sock)115 static int ripng_multicast_leave(struct interface *ifp, int sock)
116 {
117 	int ret;
118 	struct ipv6_mreq mreq;
119 
120 	if (if_is_multicast(ifp)) {
121 		memset(&mreq, 0, sizeof(mreq));
122 		inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
123 		mreq.ipv6mr_interface = ifp->ifindex;
124 
125 		ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
126 				 (char *)&mreq, sizeof(mreq));
127 		if (ret < 0)
128 			zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s",
129 				  safe_strerror(errno));
130 
131 		if (IS_RIPNG_DEBUG_EVENT)
132 			zlog_debug(
133 				"RIPng %s leave from all-rip-routers multicast group",
134 				ifp->name);
135 
136 		if (ret < 0)
137 			return -1;
138 	}
139 
140 	return 0;
141 }
142 
143 /* How many link local IPv6 address could be used on the interface ? */
ripng_if_ipv6_lladdress_check(struct interface * ifp)144 static int ripng_if_ipv6_lladdress_check(struct interface *ifp)
145 {
146 	struct listnode *nn;
147 	struct connected *connected;
148 	int count = 0;
149 
150 	for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) {
151 		struct prefix *p;
152 		p = connected->address;
153 
154 		if ((p->family == AF_INET6)
155 		    && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
156 			count++;
157 	}
158 
159 	return count;
160 }
161 
ripng_if_down(struct interface * ifp)162 static int ripng_if_down(struct interface *ifp)
163 {
164 	struct agg_node *rp;
165 	struct ripng_info *rinfo;
166 	struct ripng_interface *ri;
167 	struct ripng *ripng;
168 	struct list *list = NULL;
169 	struct listnode *listnode = NULL, *nextnode = NULL;
170 
171 	ri = ifp->info;
172 	ripng = ri->ripng;
173 
174 	if (ripng)
175 		for (rp = agg_route_top(ripng->table); rp;
176 		     rp = agg_route_next(rp))
177 			if ((list = rp->info) != NULL)
178 				for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
179 						       rinfo))
180 					if (rinfo->ifindex == ifp->ifindex)
181 						ripng_ecmp_delete(ripng, rinfo);
182 
183 
184 	if (ri->running) {
185 		if (IS_RIPNG_DEBUG_EVENT)
186 			zlog_debug("turn off %s", ifp->name);
187 
188 		/* Leave from multicast group. */
189 		if (ripng)
190 			ripng_multicast_leave(ifp, ripng->sock);
191 
192 		ri->running = 0;
193 	}
194 
195 	return 0;
196 }
197 
198 /* Inteface link up message processing. */
ripng_ifp_up(struct interface * ifp)199 static int ripng_ifp_up(struct interface *ifp)
200 {
201 	if (IS_RIPNG_DEBUG_ZEBRA) {
202 		struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
203 
204 		zlog_debug(
205 			"interface up %s vrf %s(%u) index %d flags %llx metric %d mtu %d",
206 			ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex,
207 			(unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
208 	}
209 
210 	ripng_interface_sync(ifp);
211 
212 	/* Check if this interface is RIPng enabled or not. */
213 	ripng_enable_apply(ifp);
214 
215 	/* Check for a passive interface. */
216 	ripng_passive_interface_apply(ifp);
217 
218 	/* Apply distribute list to the all interface. */
219 	ripng_distribute_update_interface(ifp);
220 
221 	return 0;
222 }
223 
224 /* Inteface link down message processing. */
ripng_ifp_down(struct interface * ifp)225 static int ripng_ifp_down(struct interface *ifp)
226 {
227 	ripng_interface_sync(ifp);
228 	ripng_if_down(ifp);
229 
230 	if (IS_RIPNG_DEBUG_ZEBRA) {
231 		struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
232 
233 		zlog_debug(
234 			"interface down %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
235 			ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex,
236 			(unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
237 	}
238 
239 	return 0;
240 }
241 
242 /* Inteface addition message from zebra. */
ripng_ifp_create(struct interface * ifp)243 static int ripng_ifp_create(struct interface *ifp)
244 {
245 	ripng_interface_sync(ifp);
246 
247 	if (IS_RIPNG_DEBUG_ZEBRA) {
248 		struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
249 
250 		zlog_debug(
251 			"RIPng interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
252 			ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex,
253 			(unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
254 	}
255 
256 	/* Check is this interface is RIP enabled or not.*/
257 	ripng_enable_apply(ifp);
258 
259 	/* Apply distribute list to the interface. */
260 	ripng_distribute_update_interface(ifp);
261 
262 	/* Check interface routemap. */
263 	ripng_if_rmap_update_interface(ifp);
264 
265 	return 0;
266 }
267 
ripng_ifp_destroy(struct interface * ifp)268 static int ripng_ifp_destroy(struct interface *ifp)
269 {
270 	struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
271 
272 	ripng_interface_sync(ifp);
273 	if (if_is_up(ifp)) {
274 		ripng_if_down(ifp);
275 	}
276 
277 	if (IS_RIPNG_DEBUG_ZEBRA)
278 		zlog_debug(
279 			"interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d",
280 			ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex,
281 			(unsigned long long)ifp->flags, ifp->metric, ifp->mtu6);
282 
283 	return 0;
284 }
285 
286 /* VRF update for an interface. */
ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS)287 int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS)
288 {
289 	struct interface *ifp;
290 	vrf_id_t new_vrf_id;
291 
292 	ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
293 					      &new_vrf_id);
294 	if (!ifp)
295 		return 0;
296 
297 	if (IS_RIPNG_DEBUG_ZEBRA) {
298 		struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
299 		struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id);
300 
301 		zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)",
302 			   ifp->name, VRF_LOGNAME(vrf), vrf_id,
303 			   VRF_LOGNAME(nvrf), new_vrf_id);
304 	}
305 
306 	if_update_to_new_vrf(ifp, new_vrf_id);
307 	ripng_interface_sync(ifp);
308 
309 	return 0;
310 }
311 
ripng_interface_clean(struct ripng * ripng)312 void ripng_interface_clean(struct ripng *ripng)
313 {
314 	struct interface *ifp;
315 	struct ripng_interface *ri;
316 
317 	FOR_ALL_INTERFACES (ripng->vrf, ifp) {
318 		ri = ifp->info;
319 
320 		ri->enable_network = 0;
321 		ri->enable_interface = 0;
322 		ri->running = 0;
323 
324 		if (ri->t_wakeup) {
325 			thread_cancel(ri->t_wakeup);
326 			ri->t_wakeup = NULL;
327 		}
328 	}
329 }
330 
ripng_apply_address_add(struct connected * ifc)331 static void ripng_apply_address_add(struct connected *ifc)
332 {
333 	struct ripng_interface *ri = ifc->ifp->info;
334 	struct ripng *ripng = ri->ripng;
335 	struct prefix_ipv6 address;
336 	struct prefix *p;
337 
338 	if (!ripng)
339 		return;
340 
341 	if (!if_is_up(ifc->ifp))
342 		return;
343 
344 	p = ifc->address;
345 
346 	memset(&address, 0, sizeof(address));
347 	address.family = p->family;
348 	address.prefix = p->u.prefix6;
349 	address.prefixlen = p->prefixlen;
350 	apply_mask_ipv6(&address);
351 
352 	/* Check if this interface is RIP enabled or not
353 	   or  Check if this address's prefix is RIP enabled */
354 	if ((ripng_enable_if_lookup(ripng, ifc->ifp->name) >= 0)
355 	    || (ripng_enable_network_lookup2(ifc) >= 0))
356 		ripng_redistribute_add(ripng, ZEBRA_ROUTE_CONNECT,
357 				       RIPNG_ROUTE_INTERFACE, &address,
358 				       ifc->ifp->ifindex, NULL, 0);
359 }
360 
ripng_interface_address_add(ZAPI_CALLBACK_ARGS)361 int ripng_interface_address_add(ZAPI_CALLBACK_ARGS)
362 {
363 	struct connected *c;
364 	struct prefix *p;
365 
366 	c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
367 					 zclient->ibuf, vrf_id);
368 
369 	if (c == NULL)
370 		return 0;
371 
372 	p = c->address;
373 
374 	if (p->family == AF_INET6) {
375 		struct ripng_interface *ri = c->ifp->info;
376 
377 		if (IS_RIPNG_DEBUG_ZEBRA)
378 			zlog_debug("RIPng connected address %s/%d add",
379 				   inet6_ntoa(p->u.prefix6), p->prefixlen);
380 
381 		/* Check is this prefix needs to be redistributed. */
382 		ripng_apply_address_add(c);
383 
384 		/* Let's try once again whether the interface could be activated
385 		 */
386 		if (!ri->running) {
387 			/* Check if this interface is RIP enabled or not.*/
388 			ripng_enable_apply(c->ifp);
389 
390 			/* Apply distribute list to the interface. */
391 			ripng_distribute_update_interface(c->ifp);
392 
393 			/* Check interface routemap. */
394 			ripng_if_rmap_update_interface(c->ifp);
395 		}
396 	}
397 
398 	return 0;
399 }
400 
ripng_apply_address_del(struct connected * ifc)401 static void ripng_apply_address_del(struct connected *ifc)
402 {
403 	struct ripng_interface *ri = ifc->ifp->info;
404 	struct ripng *ripng = ri->ripng;
405 	struct prefix_ipv6 address;
406 	struct prefix *p;
407 
408 	if (!ripng)
409 		return;
410 
411 	if (!if_is_up(ifc->ifp))
412 		return;
413 
414 	p = ifc->address;
415 
416 	memset(&address, 0, sizeof(address));
417 	address.family = p->family;
418 	address.prefix = p->u.prefix6;
419 	address.prefixlen = p->prefixlen;
420 	apply_mask_ipv6(&address);
421 
422 	ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
423 				  RIPNG_ROUTE_INTERFACE, &address,
424 				  ifc->ifp->ifindex);
425 }
426 
ripng_interface_address_delete(ZAPI_CALLBACK_ARGS)427 int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS)
428 {
429 	struct connected *ifc;
430 	struct prefix *p;
431 	char buf[INET6_ADDRSTRLEN];
432 
433 	ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
434 					   zclient->ibuf, vrf_id);
435 
436 	if (ifc) {
437 		p = ifc->address;
438 
439 		if (p->family == AF_INET6) {
440 			if (IS_RIPNG_DEBUG_ZEBRA)
441 				zlog_debug(
442 					"RIPng connected address %s/%d delete",
443 					inet_ntop(AF_INET6, &p->u.prefix6, buf,
444 						  INET6_ADDRSTRLEN),
445 					p->prefixlen);
446 
447 			/* Check wether this prefix needs to be removed. */
448 			ripng_apply_address_del(ifc);
449 		}
450 		connected_free(&ifc);
451 	}
452 
453 	return 0;
454 }
455 
456 /* Lookup RIPng enable network. */
457 /* Check wether the interface has at least a connected prefix that
458  * is within the ripng->enable_network table. */
ripng_enable_network_lookup_if(struct interface * ifp)459 static int ripng_enable_network_lookup_if(struct interface *ifp)
460 {
461 	struct ripng_interface *ri = ifp->info;
462 	struct ripng *ripng = ri->ripng;
463 	struct listnode *node;
464 	struct connected *connected;
465 	struct prefix_ipv6 address;
466 
467 	if (!ripng)
468 		return -1;
469 
470 	for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
471 		struct prefix *p;
472 		struct agg_node *n;
473 
474 		p = connected->address;
475 
476 		if (p->family == AF_INET6) {
477 			address.family = AF_INET6;
478 			address.prefix = p->u.prefix6;
479 			address.prefixlen = IPV6_MAX_BITLEN;
480 
481 			n = agg_node_match(ripng->enable_network,
482 					   (struct prefix *)&address);
483 			if (n) {
484 				agg_unlock_node(n);
485 				return 1;
486 			}
487 		}
488 	}
489 	return -1;
490 }
491 
492 /* Check wether connected is within the ripng->enable_network table. */
ripng_enable_network_lookup2(struct connected * connected)493 static int ripng_enable_network_lookup2(struct connected *connected)
494 {
495 	struct ripng_interface *ri = connected->ifp->info;
496 	struct ripng *ripng = ri->ripng;
497 	struct prefix_ipv6 address;
498 	struct prefix *p;
499 
500 	if (!ripng)
501 		return -1;
502 
503 	p = connected->address;
504 
505 	if (p->family == AF_INET6) {
506 		struct agg_node *node;
507 
508 		address.family = p->family;
509 		address.prefix = p->u.prefix6;
510 		address.prefixlen = IPV6_MAX_BITLEN;
511 
512 		/* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within
513 		 * ripng->enable_network */
514 		node = agg_node_match(ripng->enable_network,
515 				      (struct prefix *)&address);
516 
517 		if (node) {
518 			agg_unlock_node(node);
519 			return 1;
520 		}
521 	}
522 
523 	return -1;
524 }
525 
526 /* Add RIPng enable network. */
ripng_enable_network_add(struct ripng * ripng,struct prefix * p)527 int ripng_enable_network_add(struct ripng *ripng, struct prefix *p)
528 {
529 	struct agg_node *node;
530 
531 	node = agg_node_get(ripng->enable_network, p);
532 
533 	if (node->info) {
534 		agg_unlock_node(node);
535 		return NB_ERR_INCONSISTENCY;
536 	} else
537 		node->info = (void *)1;
538 
539 	/* XXX: One should find a better solution than a generic one */
540 	ripng_enable_apply_all(ripng);
541 
542 	return NB_OK;
543 }
544 
545 /* Delete RIPng enable network. */
ripng_enable_network_delete(struct ripng * ripng,struct prefix * p)546 int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p)
547 {
548 	struct agg_node *node;
549 
550 	node = agg_node_lookup(ripng->enable_network, p);
551 	if (node) {
552 		node->info = NULL;
553 
554 		/* Unlock info lock. */
555 		agg_unlock_node(node);
556 
557 		/* Unlock lookup lock. */
558 		agg_unlock_node(node);
559 
560 		return NB_OK;
561 	}
562 
563 	return NB_ERR_INCONSISTENCY;
564 }
565 
566 /* Lookup function. */
ripng_enable_if_lookup(struct ripng * ripng,const char * ifname)567 static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname)
568 {
569 	unsigned int i;
570 	char *str;
571 
572 	if (!ripng)
573 		return -1;
574 
575 	for (i = 0; i < vector_active(ripng->enable_if); i++)
576 		if ((str = vector_slot(ripng->enable_if, i)) != NULL)
577 			if (strcmp(str, ifname) == 0)
578 				return i;
579 	return -1;
580 }
581 
ripng_enable_if_add(struct ripng * ripng,const char * ifname)582 int ripng_enable_if_add(struct ripng *ripng, const char *ifname)
583 {
584 	int ret;
585 
586 	ret = ripng_enable_if_lookup(ripng, ifname);
587 	if (ret >= 0)
588 		return NB_ERR_INCONSISTENCY;
589 
590 	vector_set(ripng->enable_if, strdup(ifname));
591 
592 	ripng_enable_apply_all(ripng);
593 
594 	return NB_OK;
595 }
596 
ripng_enable_if_delete(struct ripng * ripng,const char * ifname)597 int ripng_enable_if_delete(struct ripng *ripng, const char *ifname)
598 {
599 	int index;
600 	char *str;
601 
602 	index = ripng_enable_if_lookup(ripng, ifname);
603 	if (index < 0)
604 		return NB_ERR_INCONSISTENCY;
605 
606 	str = vector_slot(ripng->enable_if, index);
607 	free(str);
608 	vector_unset(ripng->enable_if, index);
609 
610 	ripng_enable_apply_all(ripng);
611 
612 	return NB_OK;
613 }
614 
615 /* Wake up interface. */
ripng_interface_wakeup(struct thread * t)616 static int ripng_interface_wakeup(struct thread *t)
617 {
618 	struct interface *ifp;
619 	struct ripng_interface *ri;
620 
621 	/* Get interface. */
622 	ifp = THREAD_ARG(t);
623 
624 	ri = ifp->info;
625 	ri->t_wakeup = NULL;
626 
627 	/* Join to multicast group. */
628 	if (ripng_multicast_join(ifp, ri->ripng->sock) < 0) {
629 		flog_err_sys(EC_LIB_SOCKET,
630 			     "multicast join failed, interface %s not running",
631 			     ifp->name);
632 		return 0;
633 	}
634 
635 	/* Set running flag. */
636 	ri->running = 1;
637 
638 	/* Send RIP request to the interface. */
639 	ripng_request(ifp);
640 
641 	return 0;
642 }
643 
ripng_connect_set(struct interface * ifp,int set)644 static void ripng_connect_set(struct interface *ifp, int set)
645 {
646 	struct ripng_interface *ri = ifp->info;
647 	struct ripng *ripng = ri->ripng;
648 	struct listnode *node, *nnode;
649 	struct connected *connected;
650 	struct prefix_ipv6 address;
651 
652 	for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
653 		struct prefix *p;
654 		p = connected->address;
655 
656 		if (p->family != AF_INET6)
657 			continue;
658 
659 		address.family = AF_INET6;
660 		address.prefix = p->u.prefix6;
661 		address.prefixlen = p->prefixlen;
662 		apply_mask_ipv6(&address);
663 
664 		if (set) {
665 			/* Check once more wether this prefix is within a
666 			 * "network IF_OR_PREF" one */
667 			if ((ripng_enable_if_lookup(ripng, connected->ifp->name)
668 			     >= 0)
669 			    || (ripng_enable_network_lookup2(connected) >= 0))
670 				ripng_redistribute_add(
671 					ripng, ZEBRA_ROUTE_CONNECT,
672 					RIPNG_ROUTE_INTERFACE, &address,
673 					connected->ifp->ifindex, NULL, 0);
674 		} else {
675 			ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
676 						  RIPNG_ROUTE_INTERFACE,
677 						  &address,
678 						  connected->ifp->ifindex);
679 			if (ripng_redistribute_check(ripng,
680 						     ZEBRA_ROUTE_CONNECT))
681 				ripng_redistribute_add(
682 					ripng, ZEBRA_ROUTE_CONNECT,
683 					RIPNG_ROUTE_REDISTRIBUTE, &address,
684 					connected->ifp->ifindex, NULL, 0);
685 		}
686 	}
687 }
688 
689 /* Check RIPng is enabed on this interface. */
ripng_enable_apply(struct interface * ifp)690 void ripng_enable_apply(struct interface *ifp)
691 {
692 	int ret;
693 	struct ripng_interface *ri = NULL;
694 
695 	/* Check interface. */
696 	if (!if_is_up(ifp))
697 		return;
698 
699 	ri = ifp->info;
700 
701 	/* Is this interface a candidate for RIPng ? */
702 	ret = ripng_enable_network_lookup_if(ifp);
703 
704 	/* If the interface is matched. */
705 	if (ret > 0)
706 		ri->enable_network = 1;
707 	else
708 		ri->enable_network = 0;
709 
710 	/* Check interface name configuration. */
711 	ret = ripng_enable_if_lookup(ri->ripng, ifp->name);
712 	if (ret >= 0)
713 		ri->enable_interface = 1;
714 	else
715 		ri->enable_interface = 0;
716 
717 	/* any candidate interface MUST have a link-local IPv6 address */
718 	if ((!ripng_if_ipv6_lladdress_check(ifp))
719 	    && (ri->enable_network || ri->enable_interface)) {
720 		ri->enable_network = 0;
721 		ri->enable_interface = 0;
722 		zlog_warn("Interface %s does not have any link-local address",
723 			  ifp->name);
724 	}
725 
726 	/* Update running status of the interface. */
727 	if (ri->enable_network || ri->enable_interface) {
728 		zlog_info("RIPng INTERFACE ON %s", ifp->name);
729 
730 		/* Add interface wake up thread. */
731 		thread_add_timer(master, ripng_interface_wakeup, ifp, 1,
732 				 &ri->t_wakeup);
733 
734 		ripng_connect_set(ifp, 1);
735 	} else {
736 		if (ri->running) {
737 			/* Might as well clean up the route table as well
738 			 * ripng_if_down sets to 0 ri->running, and displays
739 			 *"turn off %s"
740 			 **/
741 			ripng_if_down(ifp);
742 
743 			ripng_connect_set(ifp, 0);
744 		}
745 	}
746 }
747 
748 /* Set distribute list to all interfaces. */
ripng_enable_apply_all(struct ripng * ripng)749 static void ripng_enable_apply_all(struct ripng *ripng)
750 {
751 	struct interface *ifp;
752 
753 	FOR_ALL_INTERFACES (ripng->vrf, ifp)
754 		ripng_enable_apply(ifp);
755 }
756 
757 /* Clear all network and neighbor configuration */
ripng_clean_network(struct ripng * ripng)758 void ripng_clean_network(struct ripng *ripng)
759 {
760 	unsigned int i;
761 	char *str;
762 	struct agg_node *rn;
763 
764 	/* ripng->enable_network */
765 	for (rn = agg_route_top(ripng->enable_network); rn;
766 	     rn = agg_route_next(rn))
767 		if (rn->info) {
768 			rn->info = NULL;
769 			agg_unlock_node(rn);
770 		}
771 
772 	/* ripng->enable_if */
773 	for (i = 0; i < vector_active(ripng->enable_if); i++)
774 		if ((str = vector_slot(ripng->enable_if, i)) != NULL) {
775 			free(str);
776 			vector_slot(ripng->enable_if, i) = NULL;
777 		}
778 }
779 
780 /* Utility function for looking up passive interface settings. */
ripng_passive_interface_lookup(struct ripng * ripng,const char * ifname)781 static int ripng_passive_interface_lookup(struct ripng *ripng,
782 					  const char *ifname)
783 {
784 	unsigned int i;
785 	char *str;
786 
787 	for (i = 0; i < vector_active(ripng->passive_interface); i++)
788 		if ((str = vector_slot(ripng->passive_interface, i)) != NULL)
789 			if (strcmp(str, ifname) == 0)
790 				return i;
791 	return -1;
792 }
793 
ripng_passive_interface_apply(struct interface * ifp)794 void ripng_passive_interface_apply(struct interface *ifp)
795 {
796 	int ret;
797 	struct ripng_interface *ri;
798 	struct ripng *ripng;
799 
800 	ri = ifp->info;
801 	ripng = ri->ripng;
802 	if (!ripng)
803 		return;
804 
805 	ret = ripng_passive_interface_lookup(ripng, ifp->name);
806 	if (ret < 0)
807 		ri->passive = 0;
808 	else
809 		ri->passive = 1;
810 }
811 
ripng_passive_interface_apply_all(struct ripng * ripng)812 static void ripng_passive_interface_apply_all(struct ripng *ripng)
813 {
814 	struct interface *ifp;
815 
816 	FOR_ALL_INTERFACES (ripng->vrf, ifp)
817 		ripng_passive_interface_apply(ifp);
818 }
819 
820 /* Passive interface. */
ripng_passive_interface_set(struct ripng * ripng,const char * ifname)821 int ripng_passive_interface_set(struct ripng *ripng, const char *ifname)
822 {
823 	if (ripng_passive_interface_lookup(ripng, ifname) >= 0)
824 		return NB_ERR_INCONSISTENCY;
825 
826 	vector_set(ripng->passive_interface, strdup(ifname));
827 
828 	ripng_passive_interface_apply_all(ripng);
829 
830 	return NB_OK;
831 }
832 
ripng_passive_interface_unset(struct ripng * ripng,const char * ifname)833 int ripng_passive_interface_unset(struct ripng *ripng, const char *ifname)
834 {
835 	int i;
836 	char *str;
837 
838 	i = ripng_passive_interface_lookup(ripng, ifname);
839 	if (i < 0)
840 		return NB_ERR_INCONSISTENCY;
841 
842 	str = vector_slot(ripng->passive_interface, i);
843 	free(str);
844 	vector_unset(ripng->passive_interface, i);
845 
846 	ripng_passive_interface_apply_all(ripng);
847 
848 	return NB_OK;
849 }
850 
851 /* Free all configured RIP passive-interface settings. */
ripng_passive_interface_clean(struct ripng * ripng)852 void ripng_passive_interface_clean(struct ripng *ripng)
853 {
854 	unsigned int i;
855 	char *str;
856 
857 	for (i = 0; i < vector_active(ripng->passive_interface); i++)
858 		if ((str = vector_slot(ripng->passive_interface, i)) != NULL) {
859 			free(str);
860 			vector_slot(ripng->passive_interface, i) = NULL;
861 		}
862 	ripng_passive_interface_apply_all(ripng);
863 }
864 
865 /* Write RIPng enable network and interface to the vty. */
ripng_network_write(struct vty * vty,struct ripng * ripng)866 int ripng_network_write(struct vty *vty, struct ripng *ripng)
867 {
868 	unsigned int i;
869 	const char *ifname;
870 	struct agg_node *node;
871 
872 	/* Write enable network. */
873 	for (node = agg_route_top(ripng->enable_network); node;
874 	     node = agg_route_next(node))
875 		if (node->info)
876 			vty_out(vty, "    %pRN\n", node);
877 
878 	/* Write enable interface. */
879 	for (i = 0; i < vector_active(ripng->enable_if); i++)
880 		if ((ifname = vector_slot(ripng->enable_if, i)) != NULL)
881 			vty_out(vty, "    %s\n", ifname);
882 
883 	return 0;
884 }
885 
ri_new(void)886 static struct ripng_interface *ri_new(void)
887 {
888 	struct ripng_interface *ri;
889 
890 	ri = XCALLOC(MTYPE_RIPNG_IF, sizeof(struct ripng_interface));
891 
892 	/* Set default split-horizon behavior.  If the interface is Frame
893 	   Relay or SMDS is enabled, the default value for split-horizon is
894 	   off.  But currently Zebra does detect Frame Relay or SMDS
895 	   interface.  So all interface is set to split horizon.  */
896 	ri->split_horizon =
897 		yang_get_default_enum("%s/split-horizon", RIPNG_IFACE);
898 
899 	return ri;
900 }
901 
ripng_interface_sync(struct interface * ifp)902 void ripng_interface_sync(struct interface *ifp)
903 {
904 	struct vrf *vrf;
905 
906 	vrf = vrf_lookup_by_id(ifp->vrf_id);
907 	if (vrf) {
908 		struct ripng_interface *ri;
909 
910 		ri = ifp->info;
911 		if (ri)
912 			ri->ripng = vrf->info;
913 	}
914 }
915 
ripng_if_new_hook(struct interface * ifp)916 static int ripng_if_new_hook(struct interface *ifp)
917 {
918 	ifp->info = ri_new();
919 	ripng_interface_sync(ifp);
920 
921 	return 0;
922 }
923 
924 /* Called when interface structure deleted. */
ripng_if_delete_hook(struct interface * ifp)925 static int ripng_if_delete_hook(struct interface *ifp)
926 {
927 	XFREE(MTYPE_RIPNG_IF, ifp->info);
928 	return 0;
929 }
930 
931 /* Configuration write function for ripngd. */
interface_config_write(struct vty * vty)932 static int interface_config_write(struct vty *vty)
933 {
934 	struct vrf *vrf;
935 	int write = 0;
936 
937 	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
938 		struct interface *ifp;
939 
940 		FOR_ALL_INTERFACES (vrf, ifp) {
941 			struct lyd_node *dnode;
942 
943 			dnode = yang_dnode_get(
944 				running_config->dnode,
945 				"/frr-interface:lib/interface[name='%s'][vrf='%s']",
946 				ifp->name, vrf->name);
947 			if (dnode == NULL)
948 				continue;
949 
950 			write = 1;
951 			nb_cli_show_dnode_cmds(vty, dnode, false);
952 		}
953 	}
954 
955 	return write;
956 }
957 
958 static int interface_config_write(struct vty *vty);
959 /* ripngd's interface node. */
960 static struct cmd_node interface_node = {
961 	.name = "interface",
962 	.node = INTERFACE_NODE,
963 	.parent_node = CONFIG_NODE,
964 	.prompt = "%s(config-if)# ",
965 	.config_write = interface_config_write,
966 };
967 
968 /* Initialization of interface. */
ripng_if_init(void)969 void ripng_if_init(void)
970 {
971 	/* Interface initialize. */
972 	hook_register_prio(if_add, 0, ripng_if_new_hook);
973 	hook_register_prio(if_del, 0, ripng_if_delete_hook);
974 
975 	/* Install interface node. */
976 	install_node(&interface_node);
977 	if_cmd_init();
978 	if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up,
979 			  ripng_ifp_down, ripng_ifp_destroy);
980 }
981