1 /* $NetBSD: rsrr.c,v 1.9 2003/05/16 22:59:50 dsl Exp $ */
4 * Copyright (c) 1993, 1998-2001.
5 * The University of Southern California/Information Sciences Institute.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
37 /* May 1995 -- Added support for Route Change Notification */
42 #include <sys/param.h>
43 #if (defined(BSD) && (BSD >= 199103))
47 /* Taken from prune.c */
49 * checks for scoped multicast addresses
51 #define GET_SCOPE(gt) { \
53 if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
54 for (_i = 0; _i < numvifs; _i++) \
55 if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
56 VIFM_SET(_i, (gt)->gt_scope); \
62 int rsrr_socket
; /* interface to reservation protocol */
65 * Global RSRR variables.
67 char rsrr_recv_buf
[RSRR_MAX_LEN
]; /* RSRR receive buffer */
68 char rsrr_send_buf
[RSRR_MAX_LEN
]; /* RSRR send buffer */
70 struct sockaddr_un client_addr
;
71 socklen_t client_length
= sizeof(client_addr
);
75 * Procedure definitions needed internally.
77 static void rsrr_accept(int recvlen
);
78 static void rsrr_accept_iq(void);
79 static int rsrr_accept_rq(struct rsrr_rq
*route_query
, int flags
,
80 struct gtable
*gt_notify
);
81 static int rsrr_send(int sendlen
);
82 static void rsrr_cache(struct gtable
*gt
, struct rsrr_rq
*route_query
);
84 /* Initialize RSRR socket */
89 struct sockaddr_un serv_addr
;
91 if ((rsrr_socket
= socket(AF_LOCAL
, SOCK_DGRAM
, 0)) < 0)
92 logit(LOG_ERR
, errno
, "Can't create RSRR socket");
94 unlink(RSRR_SERV_PATH
);
95 bzero((char *) &serv_addr
, sizeof(serv_addr
));
96 serv_addr
.sun_family
= AF_LOCAL
;
97 strlcpy(serv_addr
.sun_path
, RSRR_SERV_PATH
, sizeof(serv_addr
.sun_path
));
98 #if (defined(BSD) && (BSD >= 199103))
99 servlen
= offsetof(struct sockaddr_un
, sun_path
) +
100 strlen(serv_addr
.sun_path
);
101 serv_addr
.sun_len
= servlen
;
103 servlen
= sizeof(serv_addr
.sun_family
) + strlen(serv_addr
.sun_path
);
106 if (bind(rsrr_socket
, (struct sockaddr
*) &serv_addr
, servlen
) < 0)
107 logit(LOG_ERR
, errno
, "Can't bind RSRR socket");
109 if (register_input_handler(rsrr_socket
,rsrr_read
) < 0)
110 logit(LOG_WARNING
, 0, "Couldn't register RSRR as an input handler");
113 /* Read a message from the RSRR socket */
122 bzero((char *) &client_addr
, sizeof(client_addr
));
123 rsrr_recvlen
= recvfrom(rsrr_socket
, rsrr_recv_buf
, sizeof(rsrr_recv_buf
),
124 0, (struct sockaddr
*)&client_addr
, &client_length
);
125 if (rsrr_recvlen
< 0) {
127 logit(LOG_ERR
, errno
, "RSRR recvfrom");
130 /* Use of omask taken from main() */
131 omask
= sigblock(sigmask(SIGALRM
));
132 rsrr_accept(rsrr_recvlen
);
133 (void)sigsetmask(omask
);
136 /* Accept a message from the reservation protocol and take
137 * appropriate action.
143 struct rsrr_header
*rsrr
;
144 struct rsrr_rq
*route_query
;
146 if (recvlen
< RSRR_HEADER_LEN
) {
147 logit(LOG_WARNING
, 0,
148 "Received RSRR packet of %d bytes, which is less than min size",
153 rsrr
= (struct rsrr_header
*) rsrr_recv_buf
;
155 if (rsrr
->version
> RSRR_MAX_VERSION
) {
156 logit(LOG_WARNING
, 0,
157 "Received RSRR packet version %d, which I don't understand",
162 switch (rsrr
->version
) {
164 switch (rsrr
->type
) {
165 case RSRR_INITIAL_QUERY
:
166 /* Send Initial Reply to client */
167 logit(LOG_INFO
, 0, "Received Initial Query\n");
170 case RSRR_ROUTE_QUERY
:
172 if (recvlen
< RSRR_RQ_LEN
) {
173 logit(LOG_WARNING
, 0,
174 "Received Route Query of %d bytes, which is too small",
179 route_query
= (struct rsrr_rq
*) (rsrr_recv_buf
+ RSRR_HEADER_LEN
);
181 "Received Route Query for src %s grp %s notification %d",
182 inet_fmt(route_query
->source_addr
.s_addr
),
183 inet_fmt(route_query
->dest_addr
.s_addr
),
184 BIT_TST(rsrr
->flags
,RSRR_NOTIFICATION_BIT
));
185 /* Send Route Reply to client */
186 rsrr_accept_rq(route_query
,rsrr
->flags
,NULL
);
189 logit(LOG_WARNING
, 0,
190 "Received RSRR packet type %d, which I don't handle",
197 logit(LOG_WARNING
, 0,
198 "Received RSRR packet version %d, which I don't understand",
204 /* Send an Initial Reply to the reservation protocol. */
208 struct rsrr_header
*rsrr
;
209 struct rsrr_vif
*vif_list
;
213 /* Check for space. There should be room for plenty of vifs,
214 * but we should check anyway.
216 if (numvifs
> RSRR_MAX_VIFS
) {
217 logit(LOG_WARNING
, 0,
218 "Can't send RSRR Route Reply because %d is too many vifs",
224 rsrr
= (struct rsrr_header
*) rsrr_send_buf
;
226 rsrr
->type
= RSRR_INITIAL_REPLY
;
230 vif_list
= (struct rsrr_vif
*) (rsrr_send_buf
+ RSRR_HEADER_LEN
);
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
.s_addr
= v
->uv_lcl_addr
;
243 sendlen
= RSRR_HEADER_LEN
+ numvifs
*RSRR_VIF_LEN
;
246 logit(LOG_INFO
, 0, "Send RSRR Initial Reply");
250 /* Send a Route Reply to the reservation protocol. The Route Query
251 * contains the query to which we are responding. The flags contain
252 * the incoming flags from the query or, for route change
253 * notification, the flags that should be set for the reply. The
254 * kernel table entry contains the routing info to use for a route
255 * change notification.
258 rsrr_accept_rq(route_query
,flags
,gt_notify
)
259 struct rsrr_rq
*route_query
;
261 struct gtable
*gt_notify
;
263 struct rsrr_header
*rsrr
;
264 struct rsrr_rr
*route_reply
;
265 struct gtable
*gt
,local_g
;
271 rsrr
= (struct rsrr_header
*) rsrr_send_buf
;
273 rsrr
->type
= RSRR_ROUTE_REPLY
;
277 route_reply
= (struct rsrr_rr
*) (rsrr_send_buf
+ RSRR_HEADER_LEN
);
278 route_reply
->dest_addr
.s_addr
= route_query
->dest_addr
.s_addr
;
279 route_reply
->source_addr
.s_addr
= route_query
->source_addr
.s_addr
;
280 route_reply
->query_id
= route_query
->query_id
;
282 /* Blank routing entry for error. */
283 route_reply
->in_vif
= 0;
284 route_reply
->reserved
= 0;
285 route_reply
->out_vif_bm
= 0;
288 sendlen
= RSRR_RR_LEN
;
290 /* If kernel table entry is defined, then we are sending a Route Reply
291 * due to a Route Change Notification event. Use the kernel table entry
292 * to supply the routing info.
297 /* Include the routing entry. */
298 route_reply
->in_vif
= gt_notify
->gt_route
->rt_parent
;
299 route_reply
->out_vif_bm
= gt_notify
->gt_grpmems
;
301 } else if (find_src_grp(route_query
->source_addr
.s_addr
, 0,
302 route_query
->dest_addr
.s_addr
)) {
304 /* Found kernel entry. Code taken from add_table_entry() */
305 gt
= gtp
? gtp
->gt_gnext
: kernel_table
;
307 /* Include the routing entry. */
308 route_reply
->in_vif
= gt
->gt_route
->rt_parent
;
309 route_reply
->out_vif_bm
= gt
->gt_grpmems
;
311 /* Cache reply if using route change notification. */
312 if BIT_TST(flags
,RSRR_NOTIFICATION_BIT
) {
313 rsrr_cache(gt
,route_query
);
314 BIT_SET(rsrr
->flags
,RSRR_NOTIFICATION_BIT
);
318 /* No kernel entry; use routing table. */
319 r
= determine_route(route_query
->source_addr
.s_addr
);
322 /* We need to mimic what will happen if a data packet
323 * is forwarded by multicast routing -- the kernel will
324 * make an upcall and mrouted will install a route in the kernel.
325 * Our outgoing vif bitmap should reflect what that table
326 * will look like. Grab code from add_table_entry().
327 * This is gross, but it's probably better to be accurate.
331 mcastgrp
= route_query
->dest_addr
.s_addr
;
333 gt
->gt_mcastgrp
= mcastgrp
;
338 /* obtain the multicast group membership list */
339 for (i
= 0; i
< numvifs
; i
++) {
340 if (VIFM_ISSET(i
, r
->rt_children
) &&
341 !(VIFM_ISSET(i
, r
->rt_leaves
)))
342 VIFM_SET(i
, gt
->gt_grpmems
);
344 if (VIFM_ISSET(i
, r
->rt_leaves
) && grplst_mem(i
, mcastgrp
))
345 VIFM_SET(i
, gt
->gt_grpmems
);
349 gt
->gt_grpmems
&= ~gt
->gt_scope
;
351 /* Include the routing entry. */
352 route_reply
->in_vif
= gt
->gt_route
->rt_parent
;
353 route_reply
->out_vif_bm
= gt
->gt_grpmems
;
357 BIT_SET(rsrr
->flags
,RSRR_ERROR_BIT
);
362 logit(LOG_INFO
, 0, "Route Change: Send RSRR Route Reply");
365 logit(LOG_INFO
, 0, "Send RSRR Route Reply");
367 logit(LOG_INFO
, 0, "for src %s dst %s in vif %d out vif %lu\n",
368 inet_fmt(route_reply
->source_addr
.s_addr
),
369 inet_fmt(route_reply
->dest_addr
.s_addr
),
370 route_reply
->in_vif
, route_reply
->out_vif_bm
);
373 return rsrr_send(sendlen
);
376 /* Send an RSRR message. */
384 error
= sendto(rsrr_socket
, rsrr_send_buf
, sendlen
, 0,
385 (struct sockaddr
*)&client_addr
, client_length
);
387 /* Check for errors. */
389 logit(LOG_WARNING
, errno
, "Failed send on RSRR socket");
390 } else if (error
!= sendlen
) {
391 logit(LOG_WARNING
, 0,
392 "Sent only %d out of %d bytes on RSRR socket\n", error
, sendlen
);
397 /* Cache a message being sent to a client. Currently only used for
398 * caching Route Reply messages for route change notification.
401 rsrr_cache(gt
,route_query
)
403 struct rsrr_rq
*route_query
;
405 struct rsrr_cache
*rc
, **rcnp
;
406 struct rsrr_header
*rsrr
;
408 rsrr
= (struct rsrr_header
*) rsrr_send_buf
;
410 rcnp
= >
->gt_rsrr_cache
;
411 while ((rc
= *rcnp
) != NULL
) {
412 if ((rc
->route_query
.source_addr
.s_addr
==
413 route_query
->source_addr
.s_addr
) &&
414 (rc
->route_query
.dest_addr
.s_addr
==
415 route_query
->dest_addr
.s_addr
) &&
416 (!strcmp(rc
->client_addr
.sun_path
,client_addr
.sun_path
))) {
417 /* Cache entry already exists.
418 * Check if route notification bit has been cleared.
420 if (!BIT_TST(rsrr
->flags
,RSRR_NOTIFICATION_BIT
)) {
421 /* Delete cache entry. */
426 rc
->route_query
.query_id
= route_query
->query_id
;
428 "Update cached query id %ld from client %s\n",
429 rc
->route_query
.query_id
, rc
->client_addr
.sun_path
);
436 /* Cache entry doesn't already exist. Create one and insert at
439 rc
= (struct rsrr_cache
*) malloc(sizeof(struct rsrr_cache
));
441 logit(LOG_ERR
, 0, "ran out of memory");
442 rc
->route_query
.source_addr
.s_addr
= route_query
->source_addr
.s_addr
;
443 rc
->route_query
.dest_addr
.s_addr
= route_query
->dest_addr
.s_addr
;
444 rc
->route_query
.query_id
= route_query
->query_id
;
445 strlcpy(rc
->client_addr
.sun_path
, client_addr
.sun_path
,
446 sizeof(rc
->client_addr
.sun_path
));
447 rc
->client_length
= client_length
;
448 rc
->next
= gt
->gt_rsrr_cache
;
449 gt
->gt_rsrr_cache
= rc
;
450 logit(LOG_DEBUG
, 0, "Cached query id %ld from client %s\n",
451 rc
->route_query
.query_id
,rc
->client_addr
.sun_path
);
454 /* Send all the messages in the cache. Currently this is used to send
455 * all the cached Route Reply messages for route change notification.
458 rsrr_cache_send(gt
,notify
)
462 struct rsrr_cache
*rc
, **rcnp
;
466 BIT_SET(flags
,RSRR_NOTIFICATION_BIT
);
468 rcnp
= >
->gt_rsrr_cache
;
469 while ((rc
= *rcnp
) != NULL
) {
470 if (rsrr_accept_rq(&rc
->route_query
,flags
,gt
) < 0) {
471 logit(LOG_DEBUG
, 0, "Deleting cached query id %ld from client %s\n",
472 rc
->route_query
.query_id
,rc
->client_addr
.sun_path
);
473 /* Delete cache entry. */
482 /* Clean the cache by deleting all entries. */
487 struct rsrr_cache
*rc
,*rc_next
;
489 printf("cleaning cache for group %s\n",
490 inet_fmt(gt
->gt_mcastgrp
));
491 rc
= gt
->gt_rsrr_cache
;
497 gt
->gt_rsrr_cache
= NULL
;
503 unlink(RSRR_SERV_PATH
);