Annotation of embedaddon/pimdd/rsrr.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1993, 1998 by the University of Southern California
3: * All rights reserved.
4: *
5: * Permission to use, copy, modify, and distribute this software and its
6: * documentation in source and binary forms for lawful purposes
7: * and without fee is hereby granted, provided that the above copyright
8: * notice appear in all copies and that both the copyright notice and
9: * this permission notice appear in supporting documentation. and that
10: * any documentation, advertising materials, and other materials related
11: * to such distribution and use acknowledge that the software was
12: * developed by the University of Southern California, Information
13: * Sciences Institute. The name of the University may not be used to
14: * endorse or promote products derived from this software without
15: * specific prior written permission.
16: *
17: * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
18: * the suitability of this software for any purpose. THIS SOFTWARE IS
19: * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
20: * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22: *
23: * Other copyrights might apply to parts of this software and are so
24: * noted when applicable.
25: */
26:
27: /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
28: * April 1995.
29: *
30: * Modified by Kurtw Windisch (kurtw@antc.uoregon.edu) for use with
31: * Dense-mode pimd.
32: */
33:
34: /* May 1995 -- Added support for Route Change Notification */
35:
36: #ifdef RSRR
37:
38: #include "defs.h"
39: #include <sys/param.h>
40: #if (defined(BSD) && (BSD >= 199103))
41: #include <stddef.h>
42: #endif
43:
44:
45: /*
46: * Exported variables.
47: */
48: int rsrr_socket; /* interface to reservation protocol */
49:
50: /*
51: * Global RSRR variables.
52: */
53: char *rsrr_recv_buf; /* RSRR receive buffer */
54: char *rsrr_send_buf; /* RSRR send buffer */
55:
56: struct sockaddr_un client_addr;
57: int client_length = sizeof(client_addr);
58:
59:
60: /*
61: * Local functions definition
62: */
63: static void rsrr_accept __P((int recvlen));
64: static void rsrr_accept_iq __P((void));
65: static int rsrr_accept_rq __P((struct rsrr_rq *route_query, u_int8 flags,
66: struct gtable *gt_notify));
67: static void rsrr_read __P((int, fd_set *));
68: static int rsrr_send __P((int sendlen));
69: static void rsrr_cache __P((struct gtable *gt,
70: struct rsrr_rq *route_query));
71:
72: /* Initialize RSRR socket */
73: void
74: rsrr_init()
75: {
76: int servlen;
77: struct sockaddr_un serv_addr;
78:
79: rsrr_recv_buf = malloc(RSRR_MAX_LEN);
80: rsrr_send_buf = malloc(RSRR_MAX_LEN);
81:
82: if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
83: log(LOG_ERR, errno, "Can't create RSRR socket");
84:
85: unlink(RSRR_SERV_PATH);
86: bzero((char *) &serv_addr, sizeof(serv_addr));
87: serv_addr.sun_family = AF_UNIX;
88: strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
89: #if (defined(BSD) && (BSD >= 199103))
90: servlen = offsetof(struct sockaddr_un, sun_path) +
91: strlen(serv_addr.sun_path);
92: serv_addr.sun_len = servlen;
93: #else
94: servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
95: #endif
96:
97: if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
98: log(LOG_ERR, errno, "Can't bind RSRR socket");
99:
100: if (register_input_handler(rsrr_socket, rsrr_read) < 0)
101: log(LOG_ERR, 0, "Couldn't register RSRR as an input handler");
102: }
103:
104: /* Read a message from the RSRR socket */
105: static void
106: rsrr_read(f, rfd)
107: int f;
108: fd_set *rfd;
109: {
110: register int rsrr_recvlen;
111:
112: bzero((char *) &client_addr, sizeof(client_addr));
113: rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
114: 0, (struct sockaddr *)&client_addr,
115: &client_length);
116: if (rsrr_recvlen < 0) {
117: if (errno != EINTR)
118: log(LOG_ERR, errno, "RSRR recvfrom");
119: return;
120: }
121: rsrr_accept(rsrr_recvlen);
122: }
123:
124: /*
125: * Accept a message from the reservation protocol and take
126: * appropriate action.
127: */
128: static void
129: rsrr_accept(recvlen)
130: int recvlen;
131: {
132: struct rsrr_header *rsrr;
133: struct rsrr_rq *route_query;
134:
135: if (recvlen < RSRR_HEADER_LEN) {
136: log(LOG_WARNING, 0,
137: "Received RSRR packet of %d bytes, which is less than min size",
138: recvlen);
139: return;
140: }
141:
142: rsrr = (struct rsrr_header *) rsrr_recv_buf;
143:
144: if (rsrr->version > RSRR_MAX_VERSION) {
145: log(LOG_WARNING, 0,
146: "Received RSRR packet version %d, which I don't understand",
147: rsrr->version);
148: return;
149: }
150:
151: switch (rsrr->version) {
152: case 1:
153: switch (rsrr->type) {
154: case RSRR_INITIAL_QUERY:
155: /* Send Initial Reply to client */
156: IF_DEBUG(DEBUG_RSRR)
157: log(LOG_DEBUG, 0, "Received Initial Query\n");
158: rsrr_accept_iq();
159: break;
160: case RSRR_ROUTE_QUERY:
161: /* Check size */
162: if (recvlen < RSRR_RQ_LEN) {
163: log(LOG_WARNING, 0,
164: "Received Route Query of %d bytes, which is too small",
165: recvlen);
166: break;
167: }
168: /* Get the query */
169: route_query =
170: (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
171: IF_DEBUG(DEBUG_RSRR)
172: log(LOG_DEBUG, 0,
173: "Received Route Query for src %s grp %s notification %d",
174: inet_fmt(route_query->source_addr, s1),
175: inet_fmt(route_query->dest_addr, s2),
176: BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT));
177: /* Send Route Reply to client */
178: rsrr_accept_rq(route_query, rsrr->flags, (struct gtable *)NULL);
179: break;
180: default:
181: log(LOG_WARNING, 0,
182: "Received RSRR packet type %d, which I don't handle",
183: rsrr->type);
184: break;
185: }
186: break;
187:
188: default:
189: log(LOG_WARNING, 0,
190: "Received RSRR packet version %d, which I don't understand",
191: rsrr->version);
192: break;
193: }
194: }
195:
196: /* Send an Initial Reply to the reservation protocol. */
197: /*
198: * TODO: XXX: if a new interfaces come up and _IF_ the multicast routing
199: * daemon automatically include it, have to inform the RSVP daemon.
200: * However, this is not in the RSRRv1 draft (just expired and is not
201: * available anymore from the internet-draft ftp sites). Probably has to
202: * be included in RSRRv2.
203: */
204: static void
205: rsrr_accept_iq()
206: {
207: struct rsrr_header *rsrr;
208: struct rsrr_vif *vif_list;
209: struct uvif *v;
210: vifi_t vifi;
211: int sendlen;
212:
213: /* Check for space. There should be room for plenty of vifs,
214: * but we should check anyway.
215: */
216: if (numvifs > RSRR_MAX_VIFS) {
217: log(LOG_WARNING, 0,
218: "Can't send RSRR Route Reply because %d is too many vifs %d",
219: numvifs);
220: return;
221: }
222:
223: /* Set up message */
224: rsrr = (struct rsrr_header *) rsrr_send_buf;
225: rsrr->version = 1;
226: rsrr->type = RSRR_INITIAL_REPLY;
227: rsrr->flags = 0;
228: rsrr->num = numvifs;
229:
230: vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
231:
232: /* Include the vif list. */
233: for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
234: vif_list[vifi].id = vifi;
235: vif_list[vifi].status = 0;
236: if (v->uv_flags & (VIFF_DISABLED))
237: BIT_SET(vif_list[vifi].status, RSRR_DISABLED_BIT);
238: vif_list[vifi].threshold = v->uv_threshold;
239: vif_list[vifi].local_addr = v->uv_lcl_addr;
240: }
241:
242: /* Get the size. */
243: sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
244:
245: /* Send it. */
246: IF_DEBUG(DEBUG_RSRR)
247: log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
248: rsrr_send(sendlen);
249: }
250:
251: /* Send a Route Reply to the reservation protocol. The Route Query
252: * contains the query to which we are responding. The flags contain
253: * the incoming flags from the query or, for route change
254: * notification, the flags that should be set for the reply. The
255: * kernel table entry contains the routing info to use for a route
256: * change notification.
257: */
258: /* XXX: must modify if your routing table structure/search is different */
259: static int
260: rsrr_accept_rq(route_query, flags, gt_notify)
261: struct rsrr_rq *route_query;
262: u_int8 flags;
263: struct gtable *gt_notify;
264: {
265: struct rsrr_header *rsrr;
266: struct rsrr_rr *route_reply;
267: int sendlen;
268: struct gtable *gt;
269: int status_ok;
270:
271: /* Set up message */
272: rsrr = (struct rsrr_header *) rsrr_send_buf;
273: rsrr->version = 1;
274: rsrr->type = RSRR_ROUTE_REPLY;
275: rsrr->flags = flags;
276: rsrr->num = 0;
277:
278: route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
279: route_reply->dest_addr = route_query->dest_addr;
280: route_reply->source_addr = route_query->source_addr;
281: route_reply->query_id = route_query->query_id;
282:
283: /* Blank routing entry for error. */
284: route_reply->in_vif = 0;
285: route_reply->reserved = 0;
286: route_reply->out_vif_bm = 0;
287:
288: /* Get the size. */
289: sendlen = RSRR_RR_LEN;
290:
291: /* If routing table entry is defined, then we are sending a Route Reply
292: * due to a Route Change Notification event. Use the routing table entry
293: * to supply the routing info.
294: */
295: status_ok = FALSE;
296: if (gt_notify) {
297: /* Include the routing entry. */
298: route_reply->in_vif = gt_notify->incoming;
299: route_reply->out_vif_bm = gt_notify->oifs;
300: gt = gt_notify;
301: status_ok = TRUE;
302: } else if ((gt = find_route(route_query->source_addr,
303: route_query->dest_addr,
304: MRTF_SG | MRTF_WC | MRTF_PMBR,
305: DONT_CREATE)) != (struct gtable *)NULL) {
306: status_ok = TRUE;
307: route_reply->in_vif = gt->incoming;
308: route_reply->out_vif_bm = gt->oifs;
309: }
310: if (status_ok != TRUE) {
311: /* Set error bit. */
312: rsrr->flags = 0;
313: BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
314: }
315: else {
316: /* Cache reply if using route change notification. */
317: if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
318: /* TODO: XXX: Originally the rsrr_cache() call was first, but
319: * I think this is incorrect, because rsrr_cache() checks the
320: * rsrr_send_buf "flag" first.
321: */
322: BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
323: rsrr_cache(gt, route_query);
324: }
325: }
326:
327: IF_DEBUG(DEBUG_RSRR)
328: log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vifs 0x%x\n",
329: gt_notify ? "Route Change: " : "",
330: inet_fmt(route_reply->source_addr,s1),
331: inet_fmt(route_reply->dest_addr,s2),
332: route_reply->in_vif, route_reply->out_vif_bm);
333:
334: /* Send it. */
335: return rsrr_send(sendlen);
336: }
337:
338: /* Send an RSRR message. */
339: static int
340: rsrr_send(sendlen)
341: int sendlen;
342: {
343: int error;
344:
345: /* Send it. */
346: error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
347: (struct sockaddr *)&client_addr, client_length);
348:
349: /* Check for errors. */
350: if (error < 0) {
351: log(LOG_WARNING, errno, "Failed send on RSRR socket");
352: } else if (error != sendlen) {
353: log(LOG_WARNING, 0,
354: "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
355: }
356: return error;
357: }
358:
359: /* TODO: need to sort the rsrr_cache entries for faster access */
360: /* Cache a message being sent to a client. Currently only used for
361: * caching Route Reply messages for route change notification.
362: */
363: static void
364: rsrr_cache(gt, route_query)
365: struct gtable *gt;
366: struct rsrr_rq *route_query;
367: {
368: struct rsrr_cache *rc, **rcnp;
369: struct rsrr_header *rsrr;
370:
371: rsrr = (struct rsrr_header *) rsrr_send_buf;
372:
373: rcnp = >->rsrr_cache;
374: while ((rc = *rcnp) != NULL) {
375: if ((rc->route_query.source_addr ==
376: route_query->source_addr) &&
377: (rc->route_query.dest_addr ==
378: route_query->dest_addr) &&
379: (!strcmp(rc->client_addr.sun_path, client_addr.sun_path))) {
380: /* Cache entry already exists.
381: * Check if route notification bit has been cleared.
382: */
383: if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
384: /* Delete cache entry. */
385: *rcnp = rc->next;
386: free(rc);
387: } else {
388: /* Update */
389: /* TODO: XXX: No need to update iif, oifs, flags */
390: rc->route_query.query_id = route_query->query_id;
391: IF_DEBUG(DEBUG_RSRR)
392: log(LOG_DEBUG, 0,
393: "Update cached query id %ld from client %s\n",
394: rc->route_query.query_id, rc->client_addr.sun_path);
395: }
396: return;
397: }
398: rcnp = &rc->next;
399: }
400:
401: /* Cache entry doesn't already exist. Create one and insert at
402: * front of list.
403: */
404: rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
405: if (rc == NULL)
406: log(LOG_ERR, 0, "ran out of memory");
407: rc->route_query.source_addr = route_query->source_addr;
408: rc->route_query.dest_addr = route_query->dest_addr;
409: rc->route_query.query_id = route_query->query_id;
410: strcpy(rc->client_addr.sun_path, client_addr.sun_path);
411: rc->client_length = client_length;
412: rc->next = gt->rsrr_cache;
413: gt->rsrr_cache = rc;
414: IF_DEBUG(DEBUG_RSRR)
415: log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
416: rc->route_query.query_id, rc->client_addr.sun_path);
417: }
418:
419: /* Send all the messages in the cache for particular routing entry.
420: * Currently this is used to send all the cached Route Reply messages
421: * for route change notification.
422: */
423: void
424: rsrr_cache_send(gt, notify)
425: struct gtable *gt;
426: int notify;
427: {
428: struct rsrr_cache *rc, **rcnp;
429: u_int8 flags = 0;
430:
431: if (notify)
432: BIT_SET(flags, RSRR_NOTIFICATION_BIT);
433:
434: rcnp = >->rsrr_cache;
435:
436: while ((rc = *rcnp) != NULL) {
437: if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
438: IF_DEBUG(DEBUG_RSRR)
439: log(LOG_DEBUG, 0,
440: "Deleting cached query id %ld from client %s\n",
441: rc->route_query.query_id, rc->client_addr.sun_path);
442: /* Delete cache entry. */
443: *rcnp = rc->next;
444: free(rc);
445: } else {
446: rcnp = &rc->next;
447: }
448: }
449: }
450:
451: /* Clean the cache by deleting or moving all entries. */
452: /* XXX: for PIM, if the routing entry is (S,G), will try first to
453: * "transfer" the RSRR cache entry to the (*,G) or (*,*,RP) routing entry
454: * (if any). If the current routing entry is (*,G), it will move the
455: * cache entries to the (*,*,RP) routing entry (if existing).
456: * If the old and the new (iif, oifs) are the same, then no need to send
457: * route change message to the reservation daemon: just plug all entries at
458: * the front of the rsrr_cache chain.
459: */
460: void
461: rsrr_cache_clean(gt)
462: struct gtable *gt;
463: {
464: struct rsrr_cache *rc, *rc_next;
465:
466: IF_DEBUG(DEBUG_RSRR) {
467: log(LOG_DEBUG, 0, "cleaning cache for source %s and group %s",
468: inet_fmt(gt->source->address, s1),
469: inet_fmt(gt->group->group, s2));
470: }
471: rc = gt->rsrr_cache;
472: if (rc == (struct rsrr_cache *)NULL)
473: return;
474:
475: while(rc) {
476: rc_next = rc->next;
477: free(rc);
478: rc = rc_next;
479: }
480:
481: gt->rsrr_cache = (struct rsrr_cache *)NULL;
482: }
483:
484: void
485: rsrr_clean()
486: {
487: unlink(RSRR_SERV_PATH);
488: }
489:
490: #endif /* RSRR */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>