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