rsrr.c revision 1.3 1 /* $NetBSD: rsrr.c,v 1.3 1995/12/10 10:07:14 mycroft 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 register 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 __P((int recvlen));
74 static void rsrr_accept_iq __P((void));
75 static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags,
76 struct gtable *gt_notify));
77 static int rsrr_send __P((int sendlen));
78 static void rsrr_cache __P((struct gtable *gt,
79 struct rsrr_rq *route_query));
80
81 /* Initialize RSRR socket */
82 void
83 rsrr_init()
84 {
85 int servlen;
86 struct sockaddr_un serv_addr;
87
88 if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
89 log(LOG_ERR, errno, "Can't create RSRR socket");
90
91 unlink(RSRR_SERV_PATH);
92 bzero((char *) &serv_addr, sizeof(serv_addr));
93 serv_addr.sun_family = AF_UNIX;
94 strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
95 #if (defined(BSD) && (BSD >= 199103))
96 servlen = offsetof(struct sockaddr_un, sun_path) +
97 strlen(serv_addr.sun_path);
98 serv_addr.sun_len = servlen;
99 #else
100 servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
101 #endif
102
103 if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
104 log(LOG_ERR, errno, "Can't bind RSRR socket");
105
106 if (register_input_handler(rsrr_socket,rsrr_read) < 0)
107 log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
108 }
109
110 /* Read a message from the RSRR socket */
111 void
112 rsrr_read(f, rfd)
113 int f;
114 fd_set *rfd;
115 {
116 register int rsrr_recvlen;
117 register int omask;
118
119 bzero((char *) &client_addr, sizeof(client_addr));
120 rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
121 0, (struct sockaddr *)&client_addr, &client_length);
122 if (rsrr_recvlen < 0) {
123 if (errno != EINTR)
124 log(LOG_ERR, errno, "RSRR recvfrom");
125 return;
126 }
127 /* Use of omask taken from main() */
128 omask = sigblock(sigmask(SIGALRM));
129 rsrr_accept(rsrr_recvlen);
130 (void)sigsetmask(omask);
131 }
132
133 /* Accept a message from the reservation protocol and take
134 * appropriate action.
135 */
136 static void
137 rsrr_accept(recvlen)
138 int recvlen;
139 {
140 struct rsrr_header *rsrr;
141 struct rsrr_rq *route_query;
142
143 if (recvlen < RSRR_HEADER_LEN) {
144 log(LOG_WARNING, 0,
145 "Received RSRR packet of %d bytes, which is less than min size",
146 recvlen);
147 return;
148 }
149
150 rsrr = (struct rsrr_header *) rsrr_recv_buf;
151
152 if (rsrr->version > RSRR_MAX_VERSION) {
153 log(LOG_WARNING, 0,
154 "Received RSRR packet version %d, which I don't understand",
155 rsrr->version);
156 return;
157 }
158
159 switch (rsrr->version) {
160 case 1:
161 switch (rsrr->type) {
162 case RSRR_INITIAL_QUERY:
163 /* Send Initial Reply to client */
164 log(LOG_INFO, 0, "Received Initial Query\n");
165 rsrr_accept_iq();
166 break;
167 case RSRR_ROUTE_QUERY:
168 /* Check size */
169 if (recvlen < RSRR_RQ_LEN) {
170 log(LOG_WARNING, 0,
171 "Received Route Query of %d bytes, which is too small",
172 recvlen);
173 break;
174 }
175 /* Get the query */
176 route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
177 log(LOG_INFO, 0,
178 "Received Route Query for src %s grp %s notification %d",
179 inet_fmt(route_query->source_addr.s_addr, s1),
180 inet_fmt(route_query->dest_addr.s_addr,s2),
181 BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
182 /* Send Route Reply to client */
183 rsrr_accept_rq(route_query,rsrr->flags,NULL);
184 break;
185 default:
186 log(LOG_WARNING, 0,
187 "Received RSRR packet type %d, which I don't handle",
188 rsrr->type);
189 break;
190 }
191 break;
192
193 default:
194 log(LOG_WARNING, 0,
195 "Received RSRR packet version %d, which I don't understand",
196 rsrr->version);
197 break;
198 }
199 }
200
201 /* Send an Initial Reply to the reservation protocol. */
202 static void
203 rsrr_accept_iq()
204 {
205 struct rsrr_header *rsrr;
206 struct rsrr_vif *vif_list;
207 struct uvif *v;
208 int vifi, sendlen;
209
210 /* Check for space. There should be room for plenty of vifs,
211 * but we should check anyway.
212 */
213 if (numvifs > RSRR_MAX_VIFS) {
214 log(LOG_WARNING, 0,
215 "Can't send RSRR Route Reply because %d is too many vifs %d",
216 numvifs);
217 return;
218 }
219
220 /* Set up message */
221 rsrr = (struct rsrr_header *) rsrr_send_buf;
222 rsrr->version = 1;
223 rsrr->type = RSRR_INITIAL_REPLY;
224 rsrr->flags = 0;
225 rsrr->num = numvifs;
226
227 vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
228
229 /* Include the vif list. */
230 for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
231 vif_list[vifi].id = vifi;
232 vif_list[vifi].status = 0;
233 if (v->uv_flags & VIFF_DISABLED)
234 BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
235 vif_list[vifi].threshold = v->uv_threshold;
236 vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
237 }
238
239 /* Get the size. */
240 sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
241
242 /* Send it. */
243 log(LOG_INFO, 0, "Send RSRR Initial Reply");
244 rsrr_send(sendlen);
245 }
246
247 /* Send a Route Reply to the reservation protocol. The Route Query
248 * contains the query to which we are responding. The flags contain
249 * the incoming flags from the query or, for route change
250 * notification, the flags that should be set for the reply. The
251 * kernel table entry contains the routing info to use for a route
252 * change notification.
253 */
254 static int
255 rsrr_accept_rq(route_query,flags,gt_notify)
256 struct rsrr_rq *route_query;
257 int flags;
258 struct gtable *gt_notify;
259 {
260 struct rsrr_header *rsrr;
261 struct rsrr_rr *route_reply;
262 struct gtable *gt,local_g;
263 struct rtentry *r;
264 int sendlen,i;
265 u_long mcastgrp;
266
267 /* Set up message */
268 rsrr = (struct rsrr_header *) rsrr_send_buf;
269 rsrr->version = 1;
270 rsrr->type = RSRR_ROUTE_REPLY;
271 rsrr->flags = 0;
272 rsrr->num = 0;
273
274 route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
275 route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
276 route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
277 route_reply->query_id = route_query->query_id;
278
279 /* Blank routing entry for error. */
280 route_reply->in_vif = 0;
281 route_reply->reserved = 0;
282 route_reply->out_vif_bm = 0;
283
284 /* Get the size. */
285 sendlen = RSRR_RR_LEN;
286
287 /* If kernel table entry is defined, then we are sending a Route Reply
288 * due to a Route Change Notification event. Use the kernel table entry
289 * to supply the routing info.
290 */
291 if (gt_notify) {
292 /* Set flags */
293 rsrr->flags = flags;
294 /* Include the routing entry. */
295 route_reply->in_vif = gt_notify->gt_route->rt_parent;
296 route_reply->out_vif_bm = gt_notify->gt_grpmems;
297
298 } else if (find_src_grp(route_query->source_addr.s_addr, 0,
299 route_query->dest_addr.s_addr)) {
300
301 /* Found kernel entry. Code taken from add_table_entry() */
302 gt = gtp ? gtp->gt_gnext : kernel_table;
303
304 /* Include the routing entry. */
305 route_reply->in_vif = gt->gt_route->rt_parent;
306 route_reply->out_vif_bm = gt->gt_grpmems;
307
308 /* Cache reply if using route change notification. */
309 if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
310 rsrr_cache(gt,route_query);
311 BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
312 }
313
314 } else {
315 /* No kernel entry; use routing table. */
316 r = determine_route(route_query->source_addr.s_addr);
317
318 if (r != NULL) {
319 /* We need to mimic what will happen if a data packet
320 * is forwarded by multicast routing -- the kernel will
321 * make an upcall and mrouted will install a route in the kernel.
322 * Our outgoing vif bitmap should reflect what that table
323 * will look like. Grab code from add_table_entry().
324 * This is gross, but it's probably better to be accurate.
325 */
326
327 gt = &local_g;
328 mcastgrp = route_query->dest_addr.s_addr;
329
330 gt->gt_mcastgrp = mcastgrp;
331 gt->gt_grpmems = 0;
332 gt->gt_scope = 0;
333 gt->gt_route = r;
334
335 /* obtain the multicast group membership list */
336 for (i = 0; i < numvifs; i++) {
337 if (VIFM_ISSET(i, r->rt_children) &&
338 !(VIFM_ISSET(i, r->rt_leaves)))
339 VIFM_SET(i, gt->gt_grpmems);
340
341 if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
342 VIFM_SET(i, gt->gt_grpmems);
343 }
344
345 GET_SCOPE(gt);
346 gt->gt_grpmems &= ~gt->gt_scope;
347
348 /* Include the routing entry. */
349 route_reply->in_vif = gt->gt_route->rt_parent;
350 route_reply->out_vif_bm = gt->gt_grpmems;
351
352 } else {
353 /* Set error bit. */
354 BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
355 }
356 }
357
358 if (gt_notify)
359 log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
360
361 else
362 log(LOG_INFO, 0, "Send RSRR Route Reply");
363
364 log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
365 inet_fmt(route_reply->source_addr.s_addr,s1),
366 inet_fmt(route_reply->dest_addr.s_addr,s2),
367 route_reply->in_vif,route_reply->out_vif_bm);
368
369 /* Send it. */
370 return rsrr_send(sendlen);
371 }
372
373 /* Send an RSRR message. */
374 static int
375 rsrr_send(sendlen)
376 int sendlen;
377 {
378 int error;
379
380 /* Send it. */
381 error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
382 (struct sockaddr *)&client_addr, client_length);
383
384 /* Check for errors. */
385 if (error < 0) {
386 log(LOG_WARNING, errno, "Failed send on RSRR socket");
387 } else if (error != sendlen) {
388 log(LOG_WARNING, 0,
389 "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
390 }
391 return error;
392 }
393
394 /* Cache a message being sent to a client. Currently only used for
395 * caching Route Reply messages for route change notification.
396 */
397 static void
398 rsrr_cache(gt,route_query)
399 struct gtable *gt;
400 struct rsrr_rq *route_query;
401 {
402 struct rsrr_cache *rc, **rcnp;
403 struct rsrr_header *rsrr;
404
405 rsrr = (struct rsrr_header *) rsrr_send_buf;
406
407 rcnp = >->gt_rsrr_cache;
408 while ((rc = *rcnp) != NULL) {
409 if ((rc->route_query.source_addr.s_addr ==
410 route_query->source_addr.s_addr) &&
411 (rc->route_query.dest_addr.s_addr ==
412 route_query->dest_addr.s_addr) &&
413 (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
414 /* Cache entry already exists.
415 * Check if route notification bit has been cleared.
416 */
417 if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
418 /* Delete cache entry. */
419 *rcnp = rc->next;
420 free(rc);
421 } else {
422 /* Update */
423 rc->route_query.query_id = route_query->query_id;
424 log(LOG_DEBUG, 0,
425 "Update cached query id %ld from client %s\n",
426 rc->route_query.query_id, rc->client_addr.sun_path);
427 }
428 return;
429 }
430 rcnp = &rc->next;
431 }
432
433 /* Cache entry doesn't already exist. Create one and insert at
434 * front of list.
435 */
436 rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
437 if (rc == NULL)
438 log(LOG_ERR, 0, "ran out of memory");
439 rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
440 rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
441 rc->route_query.query_id = route_query->query_id;
442 strcpy(rc->client_addr.sun_path, client_addr.sun_path);
443 rc->client_length = client_length;
444 rc->next = gt->gt_rsrr_cache;
445 gt->gt_rsrr_cache = rc;
446 log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
447 rc->route_query.query_id,rc->client_addr.sun_path);
448 }
449
450 /* Send all the messages in the cache. Currently this is used to send
451 * all the cached Route Reply messages for route change notification.
452 */
453 void
454 rsrr_cache_send(gt,notify)
455 struct gtable *gt;
456 int notify;
457 {
458 struct rsrr_cache *rc, **rcnp;
459 int flags = 0;
460
461 if (notify)
462 BIT_SET(flags,RSRR_NOTIFICATION_BIT);
463
464 rcnp = >->gt_rsrr_cache;
465 while ((rc = *rcnp) != NULL) {
466 if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
467 log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
468 rc->route_query.query_id,rc->client_addr.sun_path);
469 /* Delete cache entry. */
470 *rcnp = rc->next;
471 free(rc);
472 } else {
473 rcnp = &rc->next;
474 }
475 }
476 }
477
478 /* Clean the cache by deleting all entries. */
479 void
480 rsrr_cache_clean(gt)
481 struct gtable *gt;
482 {
483 struct rsrr_cache *rc,*rc_next;
484
485 printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
486 rc = gt->gt_rsrr_cache;
487 while (rc) {
488 rc_next = rc->next;
489 free(rc);
490 rc = rc_next;
491 }
492 gt->gt_rsrr_cache = NULL;
493 }
494
495 void
496 rsrr_clean()
497 {
498 unlink(RSRR_SERV_PATH);
499 }
500
501 #endif /* RSRR */
502