]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripng_interface.c
af2b1c260a0f2ef5b0e77d174234149117f7272b
[mirror_frr.git] / ripngd / ripng_interface.c
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 /* Static utility function. */
53 static void ripng_enable_apply(struct interface *);
54 static void ripng_passive_interface_apply(struct interface *);
55 static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname);
56 static int ripng_enable_network_lookup2(struct connected *);
57 static void ripng_enable_apply_all(struct ripng *ripng);
58
59 /* Join to the all rip routers multicast group. */
60 static int ripng_multicast_join(struct interface *ifp, int sock)
61 {
62 int ret;
63 struct ipv6_mreq mreq;
64 int save_errno;
65
66 if (if_is_multicast(ifp)) {
67 memset(&mreq, 0, sizeof(mreq));
68 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
69 mreq.ipv6mr_interface = ifp->ifindex;
70
71 /*
72 * NetBSD 1.6.2 requires root to join groups on gif(4).
73 * While this is bogus, privs are available and easy to use
74 * for this call as a workaround.
75 */
76 frr_elevate_privs(&ripngd_privs) {
77
78 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
79 (char *)&mreq, sizeof(mreq));
80 save_errno = errno;
81
82 }
83
84 if (ret < 0 && save_errno == EADDRINUSE) {
85 /*
86 * Group is already joined. This occurs due to sloppy
87 * group
88 * management, in particular declining to leave the
89 * group on
90 * an interface that has just gone down.
91 */
92 zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n",
93 ifp->name);
94 return 0; /* not an error */
95 }
96
97 if (ret < 0)
98 zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s",
99 safe_strerror(save_errno));
100
101 if (IS_RIPNG_DEBUG_EVENT)
102 zlog_debug(
103 "RIPng %s join to all-rip-routers multicast group",
104 ifp->name);
105
106 if (ret < 0)
107 return -1;
108 }
109 return 0;
110 }
111
112 /* Leave from the all rip routers multicast group. */
113 static int ripng_multicast_leave(struct interface *ifp, int sock)
114 {
115 int ret;
116 struct ipv6_mreq mreq;
117
118 if (if_is_multicast(ifp)) {
119 memset(&mreq, 0, sizeof(mreq));
120 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
121 mreq.ipv6mr_interface = ifp->ifindex;
122
123 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
124 (char *)&mreq, sizeof(mreq));
125 if (ret < 0)
126 zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n",
127 safe_strerror(errno));
128
129 if (IS_RIPNG_DEBUG_EVENT)
130 zlog_debug(
131 "RIPng %s leave from all-rip-routers multicast group",
132 ifp->name);
133
134 if (ret < 0)
135 return -1;
136 }
137
138 return 0;
139 }
140
141 /* How many link local IPv6 address could be used on the interface ? */
142 static int ripng_if_ipv6_lladdress_check(struct interface *ifp)
143 {
144 struct listnode *nn;
145 struct connected *connected;
146 int count = 0;
147
148 for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) {
149 struct prefix *p;
150 p = connected->address;
151
152 if ((p->family == AF_INET6)
153 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
154 count++;
155 }
156
157 return count;
158 }
159
160 static int ripng_if_down(struct interface *ifp)
161 {
162 struct agg_node *rp;
163 struct ripng_info *rinfo;
164 struct ripng_interface *ri;
165 struct ripng *ripng;
166 struct list *list = NULL;
167 struct listnode *listnode = NULL, *nextnode = NULL;
168
169 ri = ifp->info;
170 ripng = ri->ripng;
171
172 if (ripng)
173 for (rp = agg_route_top(ripng->table); rp;
174 rp = agg_route_next(rp))
175 if ((list = rp->info) != NULL)
176 for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
177 rinfo))
178 if (rinfo->ifindex == ifp->ifindex)
179 ripng_ecmp_delete(ripng, rinfo);
180
181
182 if (ri->running) {
183 if (IS_RIPNG_DEBUG_EVENT)
184 zlog_debug("turn off %s", ifp->name);
185
186 /* Leave from multicast group. */
187 ripng_multicast_leave(ifp, ripng->sock);
188
189 ri->running = 0;
190 }
191
192 return 0;
193 }
194
195 /* Inteface link up message processing. */
196 int ripng_interface_up(int command, struct zclient *zclient,
197 zebra_size_t length, vrf_id_t vrf_id)
198 {
199 struct stream *s;
200 struct interface *ifp;
201
202 /* zebra_interface_state_read() updates interface structure in iflist.
203 */
204 s = zclient->ibuf;
205 ifp = zebra_interface_state_read(s, vrf_id);
206
207 if (ifp == NULL)
208 return 0;
209
210 if (IS_RIPNG_DEBUG_ZEBRA)
211 zlog_debug(
212 "interface up %s index %d flags %llx metric %d mtu %d",
213 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
214 ifp->metric, ifp->mtu6);
215
216 /* Check if this interface is RIPng enabled or not. */
217 ripng_enable_apply(ifp);
218
219 /* Check for a passive interface. */
220 ripng_passive_interface_apply(ifp);
221
222 /* Apply distribute list to the all interface. */
223 ripng_distribute_update_interface(ifp);
224
225 return 0;
226 }
227
228 /* Inteface link down message processing. */
229 int ripng_interface_down(int command, struct zclient *zclient,
230 zebra_size_t length, vrf_id_t vrf_id)
231 {
232 struct stream *s;
233 struct interface *ifp;
234
235 /* zebra_interface_state_read() updates interface structure in iflist.
236 */
237 s = zclient->ibuf;
238 ifp = zebra_interface_state_read(s, vrf_id);
239
240 if (ifp == NULL)
241 return 0;
242
243 ripng_if_down(ifp);
244
245 if (IS_RIPNG_DEBUG_ZEBRA)
246 zlog_debug(
247 "interface down %s index %d flags %#llx metric %d mtu %d",
248 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
249 ifp->metric, ifp->mtu6);
250
251 return 0;
252 }
253
254 /* Inteface addition message from zebra. */
255 int ripng_interface_add(int command, struct zclient *zclient,
256 zebra_size_t length, vrf_id_t vrf_id)
257 {
258 struct interface *ifp;
259
260 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
261
262 if (IS_RIPNG_DEBUG_ZEBRA)
263 zlog_debug(
264 "RIPng interface add %s index %d flags %#llx metric %d mtu %d",
265 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
266 ifp->metric, ifp->mtu6);
267
268 /* Check is this interface is RIP enabled or not.*/
269 ripng_enable_apply(ifp);
270
271 /* Apply distribute list to the interface. */
272 ripng_distribute_update_interface(ifp);
273
274 /* Check interface routemap. */
275 ripng_if_rmap_update_interface(ifp);
276
277 return 0;
278 }
279
280 int ripng_interface_delete(int command, struct zclient *zclient,
281 zebra_size_t length, vrf_id_t vrf_id)
282 {
283 struct interface *ifp;
284 struct stream *s;
285
286 s = zclient->ibuf;
287 /* zebra_interface_state_read() updates interface structure in iflist
288 */
289 ifp = zebra_interface_state_read(s, vrf_id);
290
291 if (ifp == NULL)
292 return 0;
293
294 if (if_is_up(ifp)) {
295 ripng_if_down(ifp);
296 }
297
298 zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
299 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
300 ifp->metric, ifp->mtu6);
301
302 /* To support pseudo interface do not free interface structure. */
303 /* if_delete(ifp); */
304 if_set_index(ifp, IFINDEX_INTERNAL);
305
306 return 0;
307 }
308
309 void ripng_interface_clean(struct ripng *ripng)
310 {
311 struct vrf *vrf = vrf_lookup_by_id(ripng->vrf_id);
312 struct interface *ifp;
313 struct ripng_interface *ri;
314
315 FOR_ALL_INTERFACES (vrf, ifp) {
316 ri = ifp->info;
317
318 ri->enable_network = 0;
319 ri->enable_interface = 0;
320 ri->running = 0;
321
322 if (ri->t_wakeup) {
323 thread_cancel(ri->t_wakeup);
324 ri->t_wakeup = NULL;
325 }
326 }
327 }
328
329 static void ripng_apply_address_add(struct connected *ifc)
330 {
331 struct ripng_interface *ri = ifc->ifp->info;
332 struct ripng *ripng = ri->ripng;
333 struct prefix_ipv6 address;
334 struct prefix *p;
335
336 if (!ripng)
337 return;
338
339 if (!if_is_up(ifc->ifp))
340 return;
341
342 p = ifc->address;
343
344 memset(&address, 0, sizeof(address));
345 address.family = p->family;
346 address.prefix = p->u.prefix6;
347 address.prefixlen = p->prefixlen;
348 apply_mask_ipv6(&address);
349
350 /* Check if this interface is RIP enabled or not
351 or Check if this address's prefix is RIP enabled */
352 if ((ripng_enable_if_lookup(ripng, ifc->ifp->name) >= 0)
353 || (ripng_enable_network_lookup2(ifc) >= 0))
354 ripng_redistribute_add(ripng, ZEBRA_ROUTE_CONNECT,
355 RIPNG_ROUTE_INTERFACE, &address,
356 ifc->ifp->ifindex, NULL, 0);
357 }
358
359 int ripng_interface_address_add(int command, struct zclient *zclient,
360 zebra_size_t length, vrf_id_t vrf_id)
361 {
362 struct connected *c;
363 struct prefix *p;
364
365 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
366 zclient->ibuf, vrf_id);
367
368 if (c == NULL)
369 return 0;
370
371 p = c->address;
372
373 if (p->family == AF_INET6) {
374 struct ripng_interface *ri = c->ifp->info;
375
376 if (IS_RIPNG_DEBUG_ZEBRA)
377 zlog_debug("RIPng connected address %s/%d add",
378 inet6_ntoa(p->u.prefix6), p->prefixlen);
379
380 /* Check is this prefix needs to be redistributed. */
381 ripng_apply_address_add(c);
382
383 /* Let's try once again whether the interface could be activated
384 */
385 if (!ri->running) {
386 /* Check if this interface is RIP enabled or not.*/
387 ripng_enable_apply(c->ifp);
388
389 /* Apply distribute list to the interface. */
390 ripng_distribute_update_interface(c->ifp);
391
392 /* Check interface routemap. */
393 ripng_if_rmap_update_interface(c->ifp);
394 }
395 }
396
397 return 0;
398 }
399
400 static void ripng_apply_address_del(struct connected *ifc)
401 {
402 struct ripng_interface *ri = ifc->ifp->info;
403 struct ripng *ripng = ri->ripng;
404 struct prefix_ipv6 address;
405 struct prefix *p;
406
407 if (!ripng)
408 return;
409
410 if (!if_is_up(ifc->ifp))
411 return;
412
413 p = ifc->address;
414
415 memset(&address, 0, sizeof(address));
416 address.family = p->family;
417 address.prefix = p->u.prefix6;
418 address.prefixlen = p->prefixlen;
419 apply_mask_ipv6(&address);
420
421 ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
422 RIPNG_ROUTE_INTERFACE, &address,
423 ifc->ifp->ifindex);
424 }
425
426 int ripng_interface_address_delete(int command, struct zclient *zclient,
427 zebra_size_t length, vrf_id_t vrf_id)
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. */
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. */
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. */
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. */
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. */
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
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
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. */
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
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. */
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. */
749 static void ripng_enable_apply_all(struct ripng *ripng)
750 {
751 struct vrf *vrf = vrf_lookup_by_id(ripng->vrf_id);
752 struct interface *ifp;
753
754 FOR_ALL_INTERFACES (vrf, ifp)
755 ripng_enable_apply(ifp);
756 }
757
758 /* Clear all network and neighbor configuration */
759 void ripng_clean_network(struct ripng *ripng)
760 {
761 unsigned int i;
762 char *str;
763 struct agg_node *rn;
764
765 /* ripng->enable_network */
766 for (rn = agg_route_top(ripng->enable_network); rn;
767 rn = agg_route_next(rn))
768 if (rn->info) {
769 rn->info = NULL;
770 agg_unlock_node(rn);
771 }
772
773 /* ripng->enable_if */
774 for (i = 0; i < vector_active(ripng->enable_if); i++)
775 if ((str = vector_slot(ripng->enable_if, i)) != NULL) {
776 free(str);
777 vector_slot(ripng->enable_if, i) = NULL;
778 }
779 }
780
781 /* Utility function for looking up passive interface settings. */
782 static int ripng_passive_interface_lookup(struct ripng *ripng,
783 const char *ifname)
784 {
785 unsigned int i;
786 char *str;
787
788 for (i = 0; i < vector_active(ripng->passive_interface); i++)
789 if ((str = vector_slot(ripng->passive_interface, i)) != NULL)
790 if (strcmp(str, ifname) == 0)
791 return i;
792 return -1;
793 }
794
795 void ripng_passive_interface_apply(struct interface *ifp)
796 {
797 int ret;
798 struct ripng_interface *ri;
799 struct ripng *ripng;
800
801 ri = ifp->info;
802 ripng = ri->ripng;
803 if (!ripng)
804 return;
805
806 ret = ripng_passive_interface_lookup(ripng, ifp->name);
807 if (ret < 0)
808 ri->passive = 0;
809 else
810 ri->passive = 1;
811 }
812
813 static void ripng_passive_interface_apply_all(struct ripng *ripng)
814 {
815 struct vrf *vrf = vrf_lookup_by_id(ripng->vrf_id);
816 struct interface *ifp;
817
818 FOR_ALL_INTERFACES (vrf, ifp)
819 ripng_passive_interface_apply(ifp);
820 }
821
822 /* Passive interface. */
823 int ripng_passive_interface_set(struct ripng *ripng, const char *ifname)
824 {
825 if (ripng_passive_interface_lookup(ripng, ifname) >= 0)
826 return NB_ERR_INCONSISTENCY;
827
828 vector_set(ripng->passive_interface, strdup(ifname));
829
830 ripng_passive_interface_apply_all(ripng);
831
832 return NB_OK;
833 }
834
835 int ripng_passive_interface_unset(struct ripng *ripng, const char *ifname)
836 {
837 int i;
838 char *str;
839
840 i = ripng_passive_interface_lookup(ripng, ifname);
841 if (i < 0)
842 return NB_ERR_INCONSISTENCY;
843
844 str = vector_slot(ripng->passive_interface, i);
845 free(str);
846 vector_unset(ripng->passive_interface, i);
847
848 ripng_passive_interface_apply_all(ripng);
849
850 return NB_OK;
851 }
852
853 /* Free all configured RIP passive-interface settings. */
854 void ripng_passive_interface_clean(struct ripng *ripng)
855 {
856 unsigned int i;
857 char *str;
858
859 for (i = 0; i < vector_active(ripng->passive_interface); i++)
860 if ((str = vector_slot(ripng->passive_interface, i)) != NULL) {
861 free(str);
862 vector_slot(ripng->passive_interface, i) = NULL;
863 }
864 ripng_passive_interface_apply_all(ripng);
865 }
866
867 /* Write RIPng enable network and interface to the vty. */
868 int ripng_network_write(struct vty *vty, struct ripng *ripng)
869 {
870 unsigned int i;
871 const char *ifname;
872 struct agg_node *node;
873 char buf[BUFSIZ];
874
875 /* Write enable network. */
876 for (node = agg_route_top(ripng->enable_network); node;
877 node = agg_route_next(node))
878 if (node->info) {
879 struct prefix *p = &node->p;
880 vty_out(vty, " %s/%d\n",
881 inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
882 p->prefixlen);
883 }
884
885 /* Write enable interface. */
886 for (i = 0; i < vector_active(ripng->enable_if); i++)
887 if ((ifname = vector_slot(ripng->enable_if, i)) != NULL)
888 vty_out(vty, " %s\n", ifname);
889
890 return 0;
891 }
892
893 static struct ripng_interface *ri_new(struct interface *ifp)
894 {
895 struct vrf *vrf;
896 struct ripng_interface *ri;
897
898 ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface));
899
900 vrf = vrf_lookup_by_id(ifp->vrf_id);
901 if (vrf)
902 ri->ripng = vrf->info;
903
904 /* Set default split-horizon behavior. If the interface is Frame
905 Relay or SMDS is enabled, the default value for split-horizon is
906 off. But currently Zebra does detect Frame Relay or SMDS
907 interface. So all interface is set to split horizon. */
908 ri->split_horizon =
909 yang_get_default_enum("%s/split-horizon", RIPNG_IFACE);
910
911 return ri;
912 }
913
914 static int ripng_if_new_hook(struct interface *ifp)
915 {
916 ifp->info = ri_new(ifp);
917 return 0;
918 }
919
920 /* Called when interface structure deleted. */
921 static int ripng_if_delete_hook(struct interface *ifp)
922 {
923 XFREE(MTYPE_IF, ifp->info);
924 ifp->info = NULL;
925 return 0;
926 }
927
928 /* Configuration write function for ripngd. */
929 static int interface_config_write(struct vty *vty)
930 {
931 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
932 struct interface *ifp;
933 int write = 0;
934
935 FOR_ALL_INTERFACES (vrf, ifp) {
936 struct lyd_node *dnode;
937
938 dnode = yang_dnode_get(
939 running_config->dnode,
940 "/frr-interface:lib/interface[name='%s'][vrf='%s']",
941 ifp->name, vrf->name);
942 if (dnode == NULL)
943 continue;
944
945 write = 1;
946 nb_cli_show_dnode_cmds(vty, dnode, false);
947 }
948
949 return write;
950 }
951
952 /* ripngd's interface node. */
953 static struct cmd_node interface_node = {
954 INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */
955 };
956
957 /* Initialization of interface. */
958 void ripng_if_init()
959 {
960 /* Interface initialize. */
961 hook_register_prio(if_add, 0, ripng_if_new_hook);
962 hook_register_prio(if_del, 0, ripng_if_delete_hook);
963
964 /* Install interface node. */
965 install_node(&interface_node, interface_config_write);
966 if_cmd_init();
967 }