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