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
18: * along with GNU Zebra; see the file COPYING. If not, write to the Free
19: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20: * 02111-1307, USA.
21: */
22:
23: #include <zebra.h>
24:
25: #include "linklist.h"
26: #include "if.h"
27: #include "prefix.h"
28: #include "memory.h"
29: #include "network.h"
30: #include "filter.h"
31: #include "log.h"
32: #include "stream.h"
33: #include "zclient.h"
34: #include "command.h"
35: #include "table.h"
36: #include "thread.h"
37: #include "privs.h"
38:
39: #include "ripngd/ripngd.h"
40: #include "ripngd/ripng_debug.h"
41:
42: /* If RFC2133 definition is used. */
43: #ifndef IPV6_JOIN_GROUP
44: #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
45: #endif
46: #ifndef IPV6_LEAVE_GROUP
47: #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
48: #endif
49:
50: extern struct zebra_privs_t ripngd_privs;
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 (const char *);
56: static int ripng_enable_network_lookup2 (struct connected *);
57: static void ripng_enable_apply_all (void);
58:
59: /* Join to the all rip routers multicast group. */
60: static int
61: ripng_multicast_join (struct interface *ifp)
62: {
63: int ret;
64: struct ipv6_mreq mreq;
65: int save_errno;
66:
67: if (if_is_up (ifp) && if_is_multicast (ifp)) {
68: memset (&mreq, 0, sizeof (mreq));
69: inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
70: mreq.ipv6mr_interface = ifp->ifindex;
71:
72: /*
73: * NetBSD 1.6.2 requires root to join groups on gif(4).
74: * While this is bogus, privs are available and easy to use
75: * for this call as a workaround.
76: */
77: if (ripngd_privs.change (ZPRIVS_RAISE))
78: zlog_err ("ripng_multicast_join: could not raise privs");
79:
80: ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
81: (char *) &mreq, sizeof (mreq));
82: save_errno = errno;
83:
84: if (ripngd_privs.change (ZPRIVS_LOWER))
85: zlog_err ("ripng_multicast_join: could not lower privs");
86:
87: if (ret < 0 && save_errno == EADDRINUSE)
88: {
89: /*
90: * Group is already joined. This occurs due to sloppy group
91: * management, in particular declining to leave the group on
92: * an interface that has just gone down.
93: */
94: zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name);
95: return 0; /* not an error */
96: }
97:
98: if (ret < 0)
99: zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s",
100: safe_strerror (save_errno));
101:
102: if (IS_RIPNG_DEBUG_EVENT)
103: zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name);
104:
105: if (ret < 0)
106: return -1;
107: }
108: return 0;
109: }
110:
111: /* Leave from the all rip routers multicast group. */
112: static int
113: ripng_multicast_leave (struct interface *ifp)
114: {
115: int ret;
116: struct ipv6_mreq mreq;
117:
118: if (if_is_up (ifp) && 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 (ripng->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", safe_strerror (errno));
127:
128: if (IS_RIPNG_DEBUG_EVENT)
129: zlog_debug ("RIPng %s leave from all-rip-routers multicast group",
130: ifp->name);
131:
132: if (ret < 0)
133: return -1;
134: }
135:
136: return 0;
137: }
138:
139: /* How many link local IPv6 address could be used on the interface ? */
140: static int
141: ripng_if_ipv6_lladdress_check (struct interface *ifp)
142: {
143: struct listnode *nn;
144: struct connected *connected;
145: int count = 0;
146:
147: for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected))
148: {
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
161: ripng_if_down (struct interface *ifp)
162: {
163: struct route_node *rp;
164: struct ripng_info *rinfo;
165: struct ripng_interface *ri;
166:
167: if (ripng)
168: {
169: for (rp = route_top (ripng->table); rp; rp = route_next (rp))
170: if ((rinfo = rp->info) != NULL)
171: {
172: /* Routes got through this interface. */
173: if (rinfo->ifindex == ifp->ifindex
174: && rinfo->type == ZEBRA_ROUTE_RIPNG
175: && rinfo->sub_type == RIPNG_ROUTE_RTE)
176: {
177: ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p,
178: &rinfo->nexthop,
179: rinfo->ifindex);
180:
181: ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
182: (struct prefix_ipv6 *)&rp->p,
183: rinfo->ifindex);
184: }
185: else
186: {
187: /* All redistributed routes got through this interface,
188: * but the static and system ones are kept. */
189: if ((rinfo->ifindex == ifp->ifindex) &&
190: (rinfo->type != ZEBRA_ROUTE_STATIC) &&
191: (rinfo->type != ZEBRA_ROUTE_SYSTEM))
192: ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
193: (struct prefix_ipv6 *) &rp->p,
194: rinfo->ifindex);
195: }
196: }
197: }
198:
199: ri = ifp->info;
200:
201: if (ri->running)
202: {
203: if (IS_RIPNG_DEBUG_EVENT)
204: zlog_debug ("turn off %s", ifp->name);
205:
206: /* Leave from multicast group. */
207: ripng_multicast_leave (ifp);
208:
209: ri->running = 0;
210: }
211:
212: return 0;
213: }
214:
215: /* Inteface link up message processing. */
216: int
217: ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length)
218: {
219: struct stream *s;
220: struct interface *ifp;
221:
222: /* zebra_interface_state_read() updates interface structure in iflist. */
223: s = zclient->ibuf;
224: ifp = zebra_interface_state_read (s);
225:
226: if (ifp == NULL)
227: return 0;
228:
229: if (IS_RIPNG_DEBUG_ZEBRA)
230: zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d",
231: ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
232: ifp->metric, ifp->mtu6);
233:
234: /* Check if this interface is RIPng enabled or not. */
235: ripng_enable_apply (ifp);
236:
237: /* Check for a passive interface. */
238: ripng_passive_interface_apply (ifp);
239:
240: /* Apply distribute list to the all interface. */
241: ripng_distribute_update_interface (ifp);
242:
243: return 0;
244: }
245:
246: /* Inteface link down message processing. */
247: int
248: ripng_interface_down (int command, struct zclient *zclient,
249: zebra_size_t length)
250: {
251: struct stream *s;
252: struct interface *ifp;
253:
254: /* zebra_interface_state_read() updates interface structure in iflist. */
255: s = zclient->ibuf;
256: ifp = zebra_interface_state_read (s);
257:
258: if (ifp == NULL)
259: return 0;
260:
261: ripng_if_down (ifp);
262:
263: if (IS_RIPNG_DEBUG_ZEBRA)
264: zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d",
265: ifp->name, ifp->ifindex,
266: (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6);
267:
268: return 0;
269: }
270:
271: /* Inteface addition message from zebra. */
272: int
273: ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length)
274: {
275: struct interface *ifp;
276:
277: ifp = zebra_interface_add_read (zclient->ibuf);
278:
279: if (IS_RIPNG_DEBUG_ZEBRA)
280: zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d",
281: ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
282: ifp->metric, ifp->mtu6);
283:
284: /* Check is this interface is RIP enabled or not.*/
285: ripng_enable_apply (ifp);
286:
287: /* Apply distribute list to the interface. */
288: ripng_distribute_update_interface (ifp);
289:
290: /* Check interface routemap. */
291: ripng_if_rmap_update_interface (ifp);
292:
293: return 0;
294: }
295:
296: int
297: ripng_interface_delete (int command, struct zclient *zclient,
298: zebra_size_t length)
299: {
300: struct interface *ifp;
301: struct stream *s;
302:
303: s = zclient->ibuf;
304: /* zebra_interface_state_read() updates interface structure in iflist */
305: ifp = zebra_interface_state_read(s);
306:
307: if (ifp == NULL)
308: return 0;
309:
310: if (if_is_up (ifp)) {
311: ripng_if_down(ifp);
312: }
313:
314: zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
315: ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
316: ifp->metric, ifp->mtu6);
317:
318: /* To support pseudo interface do not free interface structure. */
319: /* if_delete(ifp); */
320: ifp->ifindex = IFINDEX_INTERNAL;
321:
322: return 0;
323: }
324:
325: void
326: ripng_interface_clean (void)
327: {
328: struct listnode *node, *nnode;
329: struct interface *ifp;
330: struct ripng_interface *ri;
331:
332: for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
333: {
334: ri = ifp->info;
335:
336: ri->enable_network = 0;
337: ri->enable_interface = 0;
338: ri->running = 0;
339:
340: if (ri->t_wakeup)
341: {
342: thread_cancel (ri->t_wakeup);
343: ri->t_wakeup = NULL;
344: }
345: }
346: }
347:
348: void
349: ripng_interface_reset (void)
350: {
351: struct listnode *node;
352: struct interface *ifp;
353: struct ripng_interface *ri;
354:
355: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
356: {
357: ri = ifp->info;
358:
359: ri->enable_network = 0;
360: ri->enable_interface = 0;
361: ri->running = 0;
362:
363: ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
364: ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON;
365:
366: ri->list[RIPNG_FILTER_IN] = NULL;
367: ri->list[RIPNG_FILTER_OUT] = NULL;
368:
369: ri->prefix[RIPNG_FILTER_IN] = NULL;
370: ri->prefix[RIPNG_FILTER_OUT] = NULL;
371:
372: if (ri->t_wakeup)
373: {
374: thread_cancel (ri->t_wakeup);
375: ri->t_wakeup = NULL;
376: }
377:
378: ri->passive = 0;
379: }
380: }
381:
382: static void
383: ripng_apply_address_add (struct connected *ifc) {
384: struct prefix_ipv6 address;
385: struct prefix *p;
386:
387: if (!ripng)
388: return;
389:
390: if (! if_is_up(ifc->ifp))
391: return;
392:
393: p = ifc->address;
394:
395: memset (&address, 0, sizeof (address));
396: address.family = p->family;
397: address.prefix = p->u.prefix6;
398: address.prefixlen = p->prefixlen;
399: apply_mask_ipv6(&address);
400:
401: /* Check if this interface is RIP enabled or not
402: or Check if this address's prefix is RIP enabled */
403: if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) ||
404: (ripng_enable_network_lookup2(ifc) >= 0))
405: ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
406: &address, ifc->ifp->ifindex, NULL);
407:
408: }
409:
410: int
411: ripng_interface_address_add (int command, struct zclient *zclient,
412: zebra_size_t length)
413: {
414: struct connected *c;
415: struct prefix *p;
416:
417: c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
418: zclient->ibuf);
419:
420: if (c == NULL)
421: return 0;
422:
423: p = c->address;
424:
425: if (p->family == AF_INET6)
426: {
427: struct ripng_interface *ri = c->ifp->info;
428:
429: if (IS_RIPNG_DEBUG_ZEBRA)
430: zlog_debug ("RIPng connected address %s/%d add",
431: inet6_ntoa(p->u.prefix6),
432: p->prefixlen);
433:
434: /* Check is this prefix needs to be redistributed. */
435: ripng_apply_address_add(c);
436:
437: /* Let's try once again whether the interface could be activated */
438: if (!ri->running) {
439: /* Check if this interface is RIP enabled or not.*/
440: ripng_enable_apply (c->ifp);
441:
442: /* Apply distribute list to the interface. */
443: ripng_distribute_update_interface (c->ifp);
444:
445: /* Check interface routemap. */
446: ripng_if_rmap_update_interface (c->ifp);
447: }
448:
449: }
450:
451: return 0;
452: }
453:
454: static void
455: ripng_apply_address_del (struct connected *ifc) {
456: struct prefix_ipv6 address;
457: struct prefix *p;
458:
459: if (!ripng)
460: return;
461:
462: if (! if_is_up(ifc->ifp))
463: return;
464:
465: p = ifc->address;
466:
467: memset (&address, 0, sizeof (address));
468: address.family = p->family;
469: address.prefix = p->u.prefix6;
470: address.prefixlen = p->prefixlen;
471: apply_mask_ipv6(&address);
472:
473: ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
474: &address, ifc->ifp->ifindex);
475: }
476:
477: int
478: ripng_interface_address_delete (int command, struct zclient *zclient,
479: zebra_size_t length)
480: {
481: struct connected *ifc;
482: struct prefix *p;
483: char buf[INET6_ADDRSTRLEN];
484:
485: ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE,
486: zclient->ibuf);
487:
488: if (ifc)
489: {
490: p = ifc->address;
491:
492: if (p->family == AF_INET6)
493: {
494: if (IS_RIPNG_DEBUG_ZEBRA)
495: zlog_debug ("RIPng connected address %s/%d delete",
496: inet_ntop (AF_INET6, &p->u.prefix6, buf,
497: INET6_ADDRSTRLEN),
498: p->prefixlen);
499:
500: /* Check wether this prefix needs to be removed. */
501: ripng_apply_address_del(ifc);
502: }
503: connected_free (ifc);
504: }
505:
506: return 0;
507: }
508:
509: /* RIPng enable interface vector. */
510: vector ripng_enable_if;
511:
512: /* RIPng enable network table. */
513: struct route_table *ripng_enable_network;
514:
515: /* Lookup RIPng enable network. */
516: /* Check wether the interface has at least a connected prefix that
517: * is within the ripng_enable_network table. */
518: static int
519: ripng_enable_network_lookup_if (struct interface *ifp)
520: {
521: struct listnode *node;
522: struct connected *connected;
523: struct prefix_ipv6 address;
524:
525: for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
526: {
527: struct prefix *p;
528: struct route_node *node;
529:
530: p = connected->address;
531:
532: if (p->family == AF_INET6)
533: {
534: address.family = AF_INET6;
535: address.prefix = p->u.prefix6;
536: address.prefixlen = IPV6_MAX_BITLEN;
537:
538: node = route_node_match (ripng_enable_network,
539: (struct prefix *)&address);
540: if (node)
541: {
542: route_unlock_node (node);
543: return 1;
544: }
545: }
546: }
547: return -1;
548: }
549:
550: /* Check wether connected is within the ripng_enable_network table. */
551: static int
552: ripng_enable_network_lookup2 (struct connected *connected)
553: {
554: struct prefix_ipv6 address;
555: struct prefix *p;
556:
557: p = connected->address;
558:
559: if (p->family == AF_INET6) {
560: struct route_node *node;
561:
562: address.family = p->family;
563: address.prefix = p->u.prefix6;
564: address.prefixlen = IPV6_MAX_BITLEN;
565:
566: /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */
567: node = route_node_match (ripng_enable_network,
568: (struct prefix *)&address);
569:
570: if (node) {
571: route_unlock_node (node);
572: return 1;
573: }
574: }
575:
576: return -1;
577: }
578:
579: /* Add RIPng enable network. */
580: static int
581: ripng_enable_network_add (struct prefix *p)
582: {
583: struct route_node *node;
584:
585: node = route_node_get (ripng_enable_network, p);
586:
587: if (node->info)
588: {
589: route_unlock_node (node);
590: return -1;
591: }
592: else
593: node->info = (char *) "enabled";
594:
595: /* XXX: One should find a better solution than a generic one */
596: ripng_enable_apply_all();
597:
598: return 1;
599: }
600:
601: /* Delete RIPng enable network. */
602: static int
603: ripng_enable_network_delete (struct prefix *p)
604: {
605: struct route_node *node;
606:
607: node = route_node_lookup (ripng_enable_network, p);
608: if (node)
609: {
610: node->info = NULL;
611:
612: /* Unlock info lock. */
613: route_unlock_node (node);
614:
615: /* Unlock lookup lock. */
616: route_unlock_node (node);
617:
618: return 1;
619: }
620: return -1;
621: }
622:
623: /* Lookup function. */
624: static int
625: ripng_enable_if_lookup (const char *ifname)
626: {
627: unsigned int i;
628: char *str;
629:
630: for (i = 0; i < vector_active (ripng_enable_if); i++)
631: if ((str = vector_slot (ripng_enable_if, i)) != NULL)
632: if (strcmp (str, ifname) == 0)
633: return i;
634: return -1;
635: }
636:
637: /* Add interface to ripng_enable_if. */
638: static int
639: ripng_enable_if_add (const char *ifname)
640: {
641: int ret;
642:
643: ret = ripng_enable_if_lookup (ifname);
644: if (ret >= 0)
645: return -1;
646:
647: vector_set (ripng_enable_if, strdup (ifname));
648:
649: ripng_enable_apply_all();
650:
651: return 1;
652: }
653:
654: /* Delete interface from ripng_enable_if. */
655: static int
656: ripng_enable_if_delete (const char *ifname)
657: {
658: int index;
659: char *str;
660:
661: index = ripng_enable_if_lookup (ifname);
662: if (index < 0)
663: return -1;
664:
665: str = vector_slot (ripng_enable_if, index);
666: free (str);
667: vector_unset (ripng_enable_if, index);
668:
669: ripng_enable_apply_all();
670:
671: return 1;
672: }
673:
674: /* Wake up interface. */
675: static int
676: ripng_interface_wakeup (struct thread *t)
677: {
678: struct interface *ifp;
679: struct ripng_interface *ri;
680:
681: /* Get interface. */
682: ifp = THREAD_ARG (t);
683:
684: ri = ifp->info;
685: ri->t_wakeup = NULL;
686:
687: /* Join to multicast group. */
688: if (ripng_multicast_join (ifp) < 0) {
689: zlog_err ("multicast join failed, interface %s not running", ifp->name);
690: return 0;
691: }
692:
693: /* Set running flag. */
694: ri->running = 1;
695:
696: /* Send RIP request to the interface. */
697: ripng_request (ifp);
698:
699: return 0;
700: }
701:
702: static void
703: ripng_connect_set (struct interface *ifp, int set)
704: {
705: struct listnode *node, *nnode;
706: struct connected *connected;
707: struct prefix_ipv6 address;
708:
709: for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
710: {
711: struct prefix *p;
712: p = connected->address;
713:
714: if (p->family != AF_INET6)
715: continue;
716:
717: address.family = AF_INET6;
718: address.prefix = p->u.prefix6;
719: address.prefixlen = p->prefixlen;
720: apply_mask_ipv6 (&address);
721:
722: if (set) {
723: /* Check once more wether this prefix is within a "network IF_OR_PREF" one */
724: if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) ||
725: (ripng_enable_network_lookup2(connected) >= 0))
726: ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
727: &address, connected->ifp->ifindex, NULL);
728: } else {
729: ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
730: &address, connected->ifp->ifindex);
731: if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT))
732: ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE,
733: &address, connected->ifp->ifindex, NULL);
734: }
735: }
736: }
737:
738: /* Check RIPng is enabed on this interface. */
739: void
740: ripng_enable_apply (struct interface *ifp)
741: {
742: int ret;
743: struct ripng_interface *ri = NULL;
744:
745: /* Check interface. */
746: if (! if_is_up (ifp))
747: return;
748:
749: ri = ifp->info;
750:
751: /* Is this interface a candidate for RIPng ? */
752: ret = ripng_enable_network_lookup_if (ifp);
753:
754: /* If the interface is matched. */
755: if (ret > 0)
756: ri->enable_network = 1;
757: else
758: ri->enable_network = 0;
759:
760: /* Check interface name configuration. */
761: ret = ripng_enable_if_lookup (ifp->name);
762: if (ret >= 0)
763: ri->enable_interface = 1;
764: else
765: ri->enable_interface = 0;
766:
767: /* any candidate interface MUST have a link-local IPv6 address */
768: if ((! ripng_if_ipv6_lladdress_check (ifp)) &&
769: (ri->enable_network || ri->enable_interface)) {
770: ri->enable_network = 0;
771: ri->enable_interface = 0;
772: zlog_warn("Interface %s does not have any link-local address",
773: ifp->name);
774: }
775:
776: /* Update running status of the interface. */
777: if (ri->enable_network || ri->enable_interface)
778: {
779: {
780: if (IS_RIPNG_DEBUG_EVENT)
781: zlog_debug ("RIPng turn on %s", ifp->name);
782:
783: /* Add interface wake up thread. */
784: if (! ri->t_wakeup)
785: ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
786: ifp, 1);
787:
788: ripng_connect_set (ifp, 1);
789: }
790: }
791: else
792: {
793: if (ri->running)
794: {
795: /* Might as well clean up the route table as well
796: * ripng_if_down sets to 0 ri->running, and displays "turn off %s"
797: **/
798: ripng_if_down(ifp);
799:
800: ripng_connect_set (ifp, 0);
801: }
802: }
803: }
804:
805: /* Set distribute list to all interfaces. */
806: static void
807: ripng_enable_apply_all (void)
808: {
809: struct interface *ifp;
810: struct listnode *node;
811:
812: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
813: ripng_enable_apply (ifp);
814: }
815:
816: /* Clear all network and neighbor configuration */
817: void
818: ripng_clean_network ()
819: {
820: unsigned int i;
821: char *str;
822: struct route_node *rn;
823:
824: /* ripng_enable_network */
825: for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn))
826: if (rn->info) {
827: rn->info = NULL;
828: route_unlock_node(rn);
829: }
830:
831: /* ripng_enable_if */
832: for (i = 0; i < vector_active (ripng_enable_if); i++)
833: if ((str = vector_slot (ripng_enable_if, i)) != NULL) {
834: free (str);
835: vector_slot (ripng_enable_if, i) = NULL;
836: }
837: }
838:
839: /* Vector to store passive-interface name. */
840: vector Vripng_passive_interface;
841:
842: /* Utility function for looking up passive interface settings. */
843: static int
844: ripng_passive_interface_lookup (const char *ifname)
845: {
846: unsigned int i;
847: char *str;
848:
849: for (i = 0; i < vector_active (Vripng_passive_interface); i++)
850: if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
851: if (strcmp (str, ifname) == 0)
852: return i;
853: return -1;
854: }
855:
856: void
857: ripng_passive_interface_apply (struct interface *ifp)
858: {
859: int ret;
860: struct ripng_interface *ri;
861:
862: ri = ifp->info;
863:
864: ret = ripng_passive_interface_lookup (ifp->name);
865: if (ret < 0)
866: ri->passive = 0;
867: else
868: ri->passive = 1;
869: }
870:
871: static void
872: ripng_passive_interface_apply_all (void)
873: {
874: struct interface *ifp;
875: struct listnode *node;
876:
877: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
878: ripng_passive_interface_apply (ifp);
879: }
880:
881: /* Passive interface. */
882: static int
883: ripng_passive_interface_set (struct vty *vty, const char *ifname)
884: {
885: if (ripng_passive_interface_lookup (ifname) >= 0)
886: return CMD_WARNING;
887:
888: vector_set (Vripng_passive_interface, strdup (ifname));
889:
890: ripng_passive_interface_apply_all ();
891:
892: return CMD_SUCCESS;
893: }
894:
895: static int
896: ripng_passive_interface_unset (struct vty *vty, const char *ifname)
897: {
898: int i;
899: char *str;
900:
901: i = ripng_passive_interface_lookup (ifname);
902: if (i < 0)
903: return CMD_WARNING;
904:
905: str = vector_slot (Vripng_passive_interface, i);
906: free (str);
907: vector_unset (Vripng_passive_interface, i);
908:
909: ripng_passive_interface_apply_all ();
910:
911: return CMD_SUCCESS;
912: }
913:
914: /* Free all configured RIP passive-interface settings. */
915: void
916: ripng_passive_interface_clean (void)
917: {
918: unsigned int i;
919: char *str;
920:
921: for (i = 0; i < vector_active (Vripng_passive_interface); i++)
922: if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
923: {
924: free (str);
925: vector_slot (Vripng_passive_interface, i) = NULL;
926: }
927: ripng_passive_interface_apply_all ();
928: }
929:
930: /* Write RIPng enable network and interface to the vty. */
931: int
932: ripng_network_write (struct vty *vty, int config_mode)
933: {
934: unsigned int i;
935: const char *ifname;
936: struct route_node *node;
937: char buf[BUFSIZ];
938:
939: /* Write enable network. */
940: for (node = route_top (ripng_enable_network); node; node = route_next (node))
941: if (node->info)
942: {
943: struct prefix *p = &node->p;
944: vty_out (vty, "%s%s/%d%s",
945: config_mode ? " network " : " ",
946: inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
947: p->prefixlen,
948: VTY_NEWLINE);
949:
950: }
951:
952: /* Write enable interface. */
953: for (i = 0; i < vector_active (ripng_enable_if); i++)
954: if ((ifname = vector_slot (ripng_enable_if, i)) != NULL)
955: vty_out (vty, "%s%s%s",
956: config_mode ? " network " : " ",
957: ifname,
958: VTY_NEWLINE);
959:
960: /* Write passive interface. */
961: if (config_mode)
962: for (i = 0; i < vector_active (Vripng_passive_interface); i++)
963: if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
964: vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
965:
966: return 0;
967: }
968:
969: /* RIPng enable on specified interface or matched network. */
970: DEFUN (ripng_network,
971: ripng_network_cmd,
972: "network IF_OR_ADDR",
973: "RIPng enable on specified interface or network.\n"
974: "Interface or address")
975: {
976: int ret;
977: struct prefix p;
978:
979: ret = str2prefix (argv[0], &p);
980:
981: /* Given string is IPv6 network or interface name. */
982: if (ret)
983: ret = ripng_enable_network_add (&p);
984: else
985: ret = ripng_enable_if_add (argv[0]);
986:
987: if (ret < 0)
988: {
989: vty_out (vty, "There is same network configuration %s%s", argv[0],
990: VTY_NEWLINE);
991: return CMD_WARNING;
992: }
993:
994: return CMD_SUCCESS;
995: }
996:
997: /* RIPng enable on specified interface or matched network. */
998: DEFUN (no_ripng_network,
999: no_ripng_network_cmd,
1000: "no network IF_OR_ADDR",
1001: NO_STR
1002: "RIPng enable on specified interface or network.\n"
1003: "Interface or address")
1004: {
1005: int ret;
1006: struct prefix p;
1007:
1008: ret = str2prefix (argv[0], &p);
1009:
1010: /* Given string is interface name. */
1011: if (ret)
1012: ret = ripng_enable_network_delete (&p);
1013: else
1014: ret = ripng_enable_if_delete (argv[0]);
1015:
1016: if (ret < 0)
1017: {
1018: vty_out (vty, "can't find network %s%s", argv[0],
1019: VTY_NEWLINE);
1020: return CMD_WARNING;
1021: }
1022:
1023: return CMD_SUCCESS;
1024: }
1025:
1026: DEFUN (ipv6_ripng_split_horizon,
1027: ipv6_ripng_split_horizon_cmd,
1028: "ipv6 ripng split-horizon",
1029: IPV6_STR
1030: "Routing Information Protocol\n"
1031: "Perform split horizon\n")
1032: {
1033: struct interface *ifp;
1034: struct ripng_interface *ri;
1035:
1036: ifp = vty->index;
1037: ri = ifp->info;
1038:
1039: ri->split_horizon = RIPNG_SPLIT_HORIZON;
1040: return CMD_SUCCESS;
1041: }
1042:
1043: DEFUN (ipv6_ripng_split_horizon_poisoned_reverse,
1044: ipv6_ripng_split_horizon_poisoned_reverse_cmd,
1045: "ipv6 ripng split-horizon poisoned-reverse",
1046: IPV6_STR
1047: "Routing Information Protocol\n"
1048: "Perform split horizon\n"
1049: "With poisoned-reverse\n")
1050: {
1051: struct interface *ifp;
1052: struct ripng_interface *ri;
1053:
1054: ifp = vty->index;
1055: ri = ifp->info;
1056:
1057: ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE;
1058: return CMD_SUCCESS;
1059: }
1060:
1061: DEFUN (no_ipv6_ripng_split_horizon,
1062: no_ipv6_ripng_split_horizon_cmd,
1063: "no ipv6 ripng split-horizon",
1064: NO_STR
1065: IPV6_STR
1066: "Routing Information Protocol\n"
1067: "Perform split horizon\n")
1068: {
1069: struct interface *ifp;
1070: struct ripng_interface *ri;
1071:
1072: ifp = vty->index;
1073: ri = ifp->info;
1074:
1075: ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
1076: return CMD_SUCCESS;
1077: }
1078:
1079: ALIAS (no_ipv6_ripng_split_horizon,
1080: no_ipv6_ripng_split_horizon_poisoned_reverse_cmd,
1081: "no ipv6 ripng split-horizon poisoned-reverse",
1082: NO_STR
1083: IPV6_STR
1084: "Routing Information Protocol\n"
1085: "Perform split horizon\n"
1086: "With poisoned-reverse\n")
1087:
1088: DEFUN (ripng_passive_interface,
1089: ripng_passive_interface_cmd,
1090: "passive-interface IFNAME",
1091: "Suppress routing updates on an interface\n"
1092: "Interface name\n")
1093: {
1094: return ripng_passive_interface_set (vty, argv[0]);
1095: }
1096:
1097: DEFUN (no_ripng_passive_interface,
1098: no_ripng_passive_interface_cmd,
1099: "no passive-interface IFNAME",
1100: NO_STR
1101: "Suppress routing updates on an interface\n"
1102: "Interface name\n")
1103: {
1104: return ripng_passive_interface_unset (vty, argv[0]);
1105: }
1106:
1107: static struct ripng_interface *
1108: ri_new (void)
1109: {
1110: struct ripng_interface *ri;
1111: ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
1112:
1113: /* Set default split-horizon behavior. If the interface is Frame
1114: Relay or SMDS is enabled, the default value for split-horizon is
1115: off. But currently Zebra does detect Frame Relay or SMDS
1116: interface. So all interface is set to split horizon. */
1117: ri->split_horizon_default = RIPNG_SPLIT_HORIZON;
1118: ri->split_horizon = ri->split_horizon_default;
1119:
1120: return ri;
1121: }
1122:
1123: static int
1124: ripng_if_new_hook (struct interface *ifp)
1125: {
1126: ifp->info = ri_new ();
1127: return 0;
1128: }
1129:
1130: /* Called when interface structure deleted. */
1131: static int
1132: ripng_if_delete_hook (struct interface *ifp)
1133: {
1134: XFREE (MTYPE_IF, ifp->info);
1135: ifp->info = NULL;
1136: return 0;
1137: }
1138:
1139: /* Configuration write function for ripngd. */
1140: static int
1141: interface_config_write (struct vty *vty)
1142: {
1143: struct listnode *node;
1144: struct interface *ifp;
1145: struct ripng_interface *ri;
1146: int write = 0;
1147:
1148: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
1149: {
1150: ri = ifp->info;
1151:
1152: /* Do not display the interface if there is no
1153: * configuration about it.
1154: **/
1155: if ((!ifp->desc) &&
1156: (ri->split_horizon == ri->split_horizon_default))
1157: continue;
1158:
1159: vty_out (vty, "interface %s%s", ifp->name,
1160: VTY_NEWLINE);
1161: if (ifp->desc)
1162: vty_out (vty, " description %s%s", ifp->desc,
1163: VTY_NEWLINE);
1164:
1165: /* Split horizon. */
1166: if (ri->split_horizon != ri->split_horizon_default)
1167: {
1168: switch (ri->split_horizon) {
1169: case RIPNG_SPLIT_HORIZON:
1170: vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE);
1171: break;
1172: case RIPNG_SPLIT_HORIZON_POISONED_REVERSE:
1173: vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s",
1174: VTY_NEWLINE);
1175: break;
1176: case RIPNG_NO_SPLIT_HORIZON:
1177: default:
1178: vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE);
1179: break;
1180: }
1181: }
1182:
1183: vty_out (vty, "!%s", VTY_NEWLINE);
1184:
1185: write++;
1186: }
1187: return write;
1188: }
1189:
1190: /* ripngd's interface node. */
1191: static struct cmd_node interface_node =
1192: {
1193: INTERFACE_NODE,
1194: "%s(config-if)# ",
1195: 1 /* VTYSH */
1196: };
1197:
1198: /* Initialization of interface. */
1199: void
1200: ripng_if_init ()
1201: {
1202: /* Interface initialize. */
1203: iflist = list_new ();
1204: if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
1205: if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook);
1206:
1207: /* RIPng enable network init. */
1208: ripng_enable_network = route_table_init ();
1209:
1210: /* RIPng enable interface init. */
1211: ripng_enable_if = vector_init (1);
1212:
1213: /* RIPng passive interface. */
1214: Vripng_passive_interface = vector_init (1);
1215:
1216: /* Install interface node. */
1217: install_node (&interface_node, interface_config_write);
1218:
1219: /* Install commands. */
1220: install_element (CONFIG_NODE, &interface_cmd);
1221: install_element (CONFIG_NODE, &no_interface_cmd);
1222: install_default (INTERFACE_NODE);
1223: install_element (INTERFACE_NODE, &interface_desc_cmd);
1224: install_element (INTERFACE_NODE, &no_interface_desc_cmd);
1225:
1226: install_element (RIPNG_NODE, &ripng_network_cmd);
1227: install_element (RIPNG_NODE, &no_ripng_network_cmd);
1228: install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
1229: install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
1230:
1231: install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
1232: install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1233: install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd);
1234: install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1235: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>