Annotation of embedaddon/pimdd/vif.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1998 by the University of Southern California.
3: * All rights reserved.
4: *
5: * Permission to use, copy, modify, and distribute this software and
6: * its documentation in source and binary forms for lawful
7: * purposes and without fee is hereby granted, provided
8: * that the above copyright notice appear in all copies and that both
9: * the copyright notice and this permission notice appear in supporting
10: * documentation, and that any documentation, advertising materials,
11: * and other materials related to such distribution and use acknowledge
12: * that the software was developed by the University of Southern
13: * California and/or Information Sciences Institute.
14: * The name of the University of Southern California may not
15: * be used to endorse or promote products derived from this software
16: * without specific prior written permission.
17: *
18: * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19: * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
20: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23: * NON-INFRINGEMENT.
24: *
25: * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26: * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27: * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28: * THE USE OR PERFORMANCE OF THIS SOFTWARE.
29: *
30: * Other copyrights might apply to parts of this software and are so
31: * noted when applicable.
32: */
33: /*
34: * Questions concerning this software should be directed to
35: * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
36: *
37: * $Id: vif.c,v 1.6 1998/12/22 21:50:19 kurtw Exp $
38: */
39: /*
40: * Part of this program has been derived from mrouted.
41: * The mrouted program is covered by the license in the accompanying file
42: * named "LICENSE.mrouted".
43: *
44: * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
45: * Leland Stanford Junior University.
46: *
47: */
48:
49: #include "defs.h"
50:
51: /*
52: * Exported variables.
53: */
54: struct uvif uvifs[MAXVIFS]; /* array of all virtual interfaces */
55: vifi_t numvifs; /* Number of vifs in use */
56: int vifs_down; /* 1=>some interfaces are down */
57: int phys_vif; /* An enabled vif */
58: int udp_socket; /* Since the honkin' kernel doesn't support */
59: /* ioctls on raw IP sockets, we need a UDP */
60: /* socket as well as our IGMP (raw) socket. */
61: /* How dumb. */
62: int total_interfaces; /* Number of all interfaces: including the
63: * non-configured, but excluding the
64: * loopback interface and the non-multicast
65: * capable interfaces.
66: */
67:
68: /*
69: * Forward declarations.
70: */
71: static void start_vif __P((vifi_t vifi));
72: static void stop_vif __P((vifi_t vifi));
73: static void start_all_vifs __P(());
74:
75:
76: void
77: init_vifs()
78: {
79: vifi_t vifi;
80: struct uvif *v;
81: int enabled_vifs;
82:
83: numvifs = 0;
84: vifs_down = FALSE;
85:
86: /*
87: * Configure the vifs based on the interface configuration of the
88: * the kernel and the contents of the configuration file.
89: * (Open a UDP socket for ioctl use in the config procedures if
90: * the kernel can't handle IOCTL's on the IGMP socket.)
91: */
92: #ifdef IOCTL_OK_ON_RAW_SOCKET
93: udp_socket = igmp_socket;
94: #else
95: if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
96: log(LOG_ERR, errno, "UDP socket");
97: #endif
98:
99: /*
100: * Clean up all vifs
101: */
102: for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
103: v->uv_flags = 0;
104: v->uv_metric = DEFAULT_METRIC;
105: v->uv_admetric = 0;
106: v->uv_threshold = DEFAULT_THRESHOLD;
107: v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
108: v->uv_lcl_addr = INADDR_ANY_N;
109: v->uv_rmt_addr = INADDR_ANY_N;
110: v->uv_dst_addr = INADDR_ANY_N;
111: v->uv_subnet = INADDR_ANY_N;
112: v->uv_subnetmask = INADDR_ANY_N;
113: v->uv_subnetbcast = INADDR_ANY_N;
114: strncpy(v->uv_name, "", IFNAMSIZ);
115: v->uv_groups = (struct listaddr *)NULL;
116: v->uv_dvmrp_neighbors = (struct listaddr *)NULL;
117: NBRM_CLRALL(v->uv_nbrmap);
118: v->uv_querier = (struct listaddr *)NULL;
119: v->uv_igmpv1_warn = 0;
120: v->uv_prune_lifetime = 0;
121: v->uv_acl = (struct vif_acl *)NULL;
122: RESET_TIMER(v->uv_leaf_timer);
123: v->uv_addrs = (struct phaddr *)NULL;
124: v->uv_filter = (struct vif_filter *)NULL;
125: RESET_TIMER(v->uv_pim_hello_timer);
126: RESET_TIMER(v->uv_gq_timer);
127: v->uv_pim_neighbors = (struct pim_nbr_entry *)NULL;
128: v->uv_local_pref = default_source_preference;
129: v->uv_local_metric = default_source_metric;
130: }
131:
132: log(LOG_INFO, 0, "Getting vifs from kernel");
133: config_vifs_from_kernel();
134: log(LOG_INFO, 0, "Getting vifs from %s", configfilename);
135: config_vifs_from_file();
136:
137: /*
138: * Quit if there are fewer than two enabled vifs.
139: */
140: enabled_vifs = 0;
141: phys_vif = -1;
142:
143: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
144: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
145: continue;
146: if (phys_vif == -1)
147: phys_vif = vifi;
148: enabled_vifs++;
149: }
150:
151: if (enabled_vifs < 2)
152: log(LOG_ERR, 0, "can't forward: %s",
153: enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
154:
155: k_init_pim(igmp_socket); /* Call to kernel to initiliaze structures */
156:
157: start_all_vifs();
158: }
159:
160:
161: static void
162: start_all_vifs()
163: {
164: vifi_t vifi;
165: struct uvif *v;
166:
167: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
168: /* Start vif if not DISABLED or DOWN */
169: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN)) {
170: if (v->uv_flags & VIFF_DISABLED)
171: log(LOG_INFO, 0,
172: "%s is DISABLED; vif #%u out of service",
173: v->uv_name, vifi);
174: else
175: log(LOG_INFO, 0,
176: "%s is DOWN; vif #%u out of service",
177: v->uv_name, vifi);
178: }
179: else
180: start_vif(vifi);
181: }
182: }
183:
184:
185:
186: /*
187: * stop all vifs
188: */
189: void
190: stop_all_vifs()
191: {
192: vifi_t vifi;
193:
194: for (vifi = 0; vifi < numvifs; vifi++) {
195: stop_vif(vifi);
196: }
197: }
198:
199:
200: /*
201: * Initialize the vif and add to the kernel. The vif can be either
202: * physical, tunnel (tunnels will be used in the future
203: * when this code becomes PIM multicast boarder router.
204: */
205: static void
206: start_vif(vifi)
207: vifi_t vifi;
208: {
209: struct uvif *v;
210: u_int32 src;
211:
212: v = &uvifs[vifi];
213: src = v->uv_lcl_addr;
214: /* Initialy no router on any vif */
215: v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~VIFF_DOWN;
216: SET_TIMER(v->uv_pim_hello_timer, 1 + RANDOM() % PIM_TIMER_HELLO_PERIOD);
217: RESET_TIMER(v->uv_gq_timer);
218: v->uv_pim_neighbors = (pim_nbr_entry_t *)NULL;
219:
220: /* Tell kernel to add, i.e. start this vif */
221: k_add_vif(igmp_socket, vifi, &uvifs[vifi]);
222: log(LOG_INFO, 0, "%s comes up; vif #%u now in service", v->uv_name, vifi);
223:
224: /*
225: * Join the PIM multicast group on the interface.
226: */
227: k_join(igmp_socket, allpimrouters_group, src);
228:
229: /*
230: * Join the ALL-ROUTERS multicast group on the interface.
231: * This allows mtrace requests to loop back if they are run
232: * on the multicast router.
233: */
234: k_join(igmp_socket, allrouters_group, src);
235:
236: /*
237: * Until neighbors are discovered, assume responsibility for sending
238: * periodic group membership queries to the subnet. Send the first
239: * query.
240: */
241: v->uv_flags |= VIFF_QUERIER;
242: query_groups(v);
243:
244: /*
245: * Send a probe via the new vif to look for neighbors.
246: */
247: send_pim_hello(v, PIM_TIMER_HELLO_HOLDTIME);
248: }
249:
250:
251: /*
252: * Stop a vif (either physical interface or tunnel).
253: * If we are running only PIM we don't have tunnels.
254: */
255: static void
256: stop_vif(vifi)
257: vifi_t vifi;
258: {
259: struct uvif *v;
260: struct listaddr *a;
261: register pim_nbr_entry_t *n, *next;
262: struct vif_acl *acl;
263:
264: /*
265: * TODO: make sure that the kernel viftable is
266: * consistent with the daemon table
267: */
268: v = &uvifs[vifi];
269: k_leave(igmp_socket, allpimrouters_group, v->uv_lcl_addr);
270: k_leave(igmp_socket, allrouters_group, v->uv_lcl_addr);
271: /*
272: * Discard all group addresses. (No need to tell kernel;
273: * the k_del_vif() call will clean up kernel state.)
274: */
275: while (v->uv_groups != NULL) {
276: a = v->uv_groups;
277: v->uv_groups = a->al_next;
278: free((char *)a);
279: }
280:
281: /*
282: * TODO: inform (eventually) the neighbors I am going down by sending
283: * PIM_HELLO with holdtime=0 so someone else should become a DR.
284: */
285: /* TODO: dummy! Implement it!! Any problems if don't use it? */
286: delete_vif_from_mrt(vifi);
287:
288: /*
289: * Delete the interface from the kernel's vif structure.
290: */
291: k_del_vif(igmp_socket, vifi);
292: v->uv_flags = (v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS )
293: | VIFF_DOWN;
294: RESET_TIMER(v->uv_pim_hello_timer);
295: RESET_TIMER(v->uv_gq_timer);
296: for (n = v->uv_pim_neighbors; n != NULL; n = next) {
297: next = n->next; /* Free the space for each neighbour */
298: free((char *)n);
299: }
300: v->uv_pim_neighbors = NULL;
301:
302: /* TODO: currently not used */
303: /* The Access Control List (list with the scoped addresses) */
304: while (v->uv_acl != NULL) {
305: acl = v->uv_acl;
306: v->uv_acl = acl->acl_next;
307: free((char *)acl);
308: }
309:
310: vifs_down = TRUE;
311: log(LOG_INFO, 0,
312: "%s goes down; vif #%u out of service", v->uv_name, vifi);
313: }
314:
315:
316: /*
317: * See if any interfaces have changed from up state to down, or vice versa,
318: * including any non-multicast-capable interfaces that are in use as local
319: * tunnel end-points. Ignore interfaces that have been administratively
320: * disabled.
321: */
322: void
323: check_vif_state()
324: {
325: register vifi_t vifi;
326: register struct uvif *v;
327: struct ifreq ifr;
328: static int checking_vifs = 0;
329:
330: /*
331: * XXX: TODO: True only for DVMRP?? Check.
332: * If we get an error while checking, (e.g. two interfaces go down
333: * at once, and we decide to send a prune out one of the failed ones)
334: * then don't go into an infinite loop!
335: */
336: if (checking_vifs)
337: return;
338:
339: vifs_down = FALSE;
340: checking_vifs = 1;
341: /* TODO: Check all potential interfaces!!! */
342: /* Check the physical and tunnels only */
343: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
344: if (v->uv_flags & VIFF_DISABLED)
345: continue;
346:
347: strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
348: /* get the interface flags */
349: if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
350: log(LOG_ERR, errno,
351: "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
352:
353: if (v->uv_flags & VIFF_DOWN) {
354: if (ifr.ifr_flags & IFF_UP) {
355: start_vif(vifi);
356: }
357: else vifs_down = TRUE;
358: }
359: else {
360: if (!(ifr.ifr_flags & IFF_UP)) {
361: log(LOG_NOTICE, 0,
362: "%s has gone down; vif #%u taken out of service",
363: v->uv_name, vifi);
364: stop_vif(vifi);
365: vifs_down = TRUE;
366: }
367: }
368: }
369: checking_vifs = 0;
370: }
371:
372:
373: /*
374: * If the source is directly connected to us, find the vif number for
375: * the corresponding physical interface (tunnels excluded).
376: * Local addresses are excluded.
377: * Return the vif number or NO_VIF if not found.
378: */
379: vifi_t
380: find_vif_direct(src)
381: u_int32 src;
382: {
383: vifi_t vifi;
384: register struct uvif *v;
385: register struct phaddr *p;
386:
387: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
388: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
389: continue;
390: if (src == v->uv_lcl_addr)
391: return (NO_VIF); /* src is one of our IP addresses */
392: if ((src & v->uv_subnetmask) == v->uv_subnet &&
393: ((v->uv_subnetmask == 0xffffffff) ||
394: (src != v->uv_subnetbcast)))
395: return(vifi);
396: /* Check the extra subnets for this vif */
397: /* TODO: don't think currently pimd can handle extra subnets */
398: for (p = v->uv_addrs; p; p = p->pa_next) {
399: if ((src & p->pa_subnetmask) == p->pa_subnet &&
400: ((p->pa_subnetmask == 0xffffffff) ||
401: (src != p->pa_subnetbcast)))
402: return(vifi);
403: }
404: }
405: return (NO_VIF);
406: }
407:
408:
409: /*
410: * Checks if src is local address. If "yes" return the vif index,
411: * otherwise return value is NO_VIF.
412: */
413: vifi_t
414: local_address(src)
415: u_int32 src;
416: {
417: vifi_t vifi;
418: register struct uvif *v;
419:
420: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
421: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
422: continue;
423: if (src != v->uv_lcl_addr)
424: continue;
425: else
426: return(vifi);
427: }
428: /* Returning NO_VIF means not a local address */
429: return (NO_VIF);
430: }
431:
432: /*
433: * If the source is directly connected, or is local address,
434: * find the vif number for the corresponding physical interface
435: * (tunnels excluded).
436: * Return the vif number or NO_VIF if not found.
437: */
438: vifi_t
439: find_vif_direct_local(src)
440: u_int32 src;
441: {
442: vifi_t vifi;
443: register struct uvif *v;
444: register struct phaddr *p;
445:
446: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
447: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL))
448: continue;
449: if (src == v->uv_lcl_addr)
450: return (vifi); /* src is one of our IP addresses */
451: if ((src & v->uv_subnetmask) == v->uv_subnet &&
452: ((v->uv_subnetmask == 0xffffffff) ||
453: (src != v->uv_subnetbcast)))
454: return(vifi);
455: /* Check the extra subnets for this vif */
456: /* TODO: don't think currently pimd can handle extra subnets */
457: for (p = v->uv_addrs; p; p = p->pa_next) {
458: if ((src & p->pa_subnetmask) == p->pa_subnet &&
459: ((p->pa_subnetmask == 0xffffffff) ||
460: (src != p->pa_subnetbcast)))
461: return(vifi);
462: }
463: }
464: return (NO_VIF);
465: }
466:
467: /*
468: * Returns the highest address of local vif that is UP and ENABLED.
469: */
470: u_int32
471: max_local_address()
472: {
473: vifi_t vifi;
474: struct uvif *v;
475: u_int32 max_address = 0;
476:
477: for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
478: /* Count vif if not DISABLED or DOWN */
479: if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN))
480: continue;
481: if (ntohl(v->uv_lcl_addr) > ntohl(max_address))
482: max_address = v->uv_lcl_addr;
483: }
484: return(max_address);
485: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>