2 * Copyright (c) 1993 by the University of Southern California
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation in source and binary forms for non-commercial 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.
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.
23 * Other copyrights might apply to parts of this software and are so
24 * noted when applicable.
27 /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
31 /* May 1995 -- Added support for Route Change Notification */
34 static const char rcsid[] =
35 "$FreeBSD: src/usr.sbin/mrouted/rsrr.c,v 1.8.2.1 2001/05/12 09:48:20 kris Exp $";
41 #include <sys/param.h>
43 #include <stddef.h> /* for offsetof */
49 int rsrr_socket; /* interface to reservation protocol */
52 * Global RSRR variables.
54 char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
55 char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
57 struct sockaddr_un client_addr;
58 int client_length = sizeof(client_addr);
62 * Procedure definitions needed internally.
64 static void rsrr_accept __P((int recvlen));
65 static void rsrr_accept_iq __P((void));
66 static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags,
67 struct gtable *gt_notify));
68 static void rsrr_read __P((int, fd_set *));
69 static int rsrr_send __P((int sendlen));
70 static void rsrr_cache __P((struct gtable *gt,
71 struct rsrr_rq *route_query));
73 /* Initialize RSRR socket */
78 struct sockaddr_un serv_addr;
80 if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
81 log(LOG_ERR, errno, "Can't create RSRR socket");
83 unlink(RSRR_SERV_PATH);
84 bzero((char *) &serv_addr, sizeof(serv_addr));
85 serv_addr.sun_family = AF_UNIX;
86 strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
88 servlen = offsetof(struct sockaddr_un, sun_path) +
89 strlen(serv_addr.sun_path);
90 serv_addr.sun_len = servlen;
92 servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
95 if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
96 log(LOG_ERR, errno, "Can't bind RSRR socket");
98 if (register_input_handler(rsrr_socket, rsrr_read) < 0)
99 log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
102 /* Read a message from the RSRR socket */
108 register int rsrr_recvlen;
110 bzero((char *) &client_addr, sizeof(client_addr));
111 rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
112 0, (struct sockaddr *)&client_addr, &client_length);
113 if (rsrr_recvlen < 0) {
115 log(LOG_ERR, errno, "RSRR recvfrom");
118 rsrr_accept(rsrr_recvlen);
121 /* Accept a message from the reservation protocol and take
122 * appropriate action.
128 struct rsrr_header *rsrr;
129 struct rsrr_rq *route_query;
131 if (recvlen < RSRR_HEADER_LEN) {
133 "Received RSRR packet of %d bytes, which is less than min size",
138 rsrr = (struct rsrr_header *) rsrr_recv_buf;
140 if (rsrr->version > RSRR_MAX_VERSION) {
142 "Received RSRR packet version %d, which I don't understand",
147 switch (rsrr->version) {
149 switch (rsrr->type) {
150 case RSRR_INITIAL_QUERY:
151 /* Send Initial Reply to client */
153 log(LOG_DEBUG, 0, "Received Initial Query\n");
156 case RSRR_ROUTE_QUERY:
158 if (recvlen < RSRR_RQ_LEN) {
160 "Received Route Query of %d bytes, which is too small",
165 route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
168 "Received Route Query for src %s grp %s notification %d",
169 inet_fmt(route_query->source_addr.s_addr, s1),
170 inet_fmt(route_query->dest_addr.s_addr,s2),
171 BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
172 /* Send Route Reply to client */
173 rsrr_accept_rq(route_query,rsrr->flags,NULL);
177 "Received RSRR packet type %d, which I don't handle",
185 "Received RSRR packet version %d, which I don't understand",
191 /* Send an Initial Reply to the reservation protocol. */
195 struct rsrr_header *rsrr;
196 struct rsrr_vif *vif_list;
200 /* Check for space. There should be room for plenty of vifs,
201 * but we should check anyway.
203 if (numvifs > RSRR_MAX_VIFS) {
205 "Can't send RSRR Route Reply because %d is too many vifs",
211 rsrr = (struct rsrr_header *) rsrr_send_buf;
213 rsrr->type = RSRR_INITIAL_REPLY;
217 vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
219 /* Include the vif list. */
220 for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
221 vif_list[vifi].id = vifi;
222 vif_list[vifi].status = 0;
223 if (v->uv_flags & VIFF_DISABLED)
224 BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
225 vif_list[vifi].threshold = v->uv_threshold;
226 vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
230 sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
234 log(LOG_DEBUG, 0, "Send RSRR Initial Reply");
238 /* Send a Route Reply to the reservation protocol. The Route Query
239 * contains the query to which we are responding. The flags contain
240 * the incoming flags from the query or, for route change
241 * notification, the flags that should be set for the reply. The
242 * kernel table entry contains the routing info to use for a route
243 * change notification.
246 rsrr_accept_rq(route_query,flags,gt_notify)
247 struct rsrr_rq *route_query;
249 struct gtable *gt_notify;
251 struct rsrr_header *rsrr;
252 struct rsrr_rr *route_reply;
253 struct gtable *gt,local_g;
259 rsrr = (struct rsrr_header *) rsrr_send_buf;
261 rsrr->type = RSRR_ROUTE_REPLY;
265 route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
266 route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
267 route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
268 route_reply->query_id = route_query->query_id;
270 /* Blank routing entry for error. */
271 route_reply->in_vif = 0;
272 route_reply->reserved = 0;
273 route_reply->out_vif_bm = 0;
276 sendlen = RSRR_RR_LEN;
278 /* If kernel table entry is defined, then we are sending a Route Reply
279 * due to a Route Change Notification event. Use the kernel table entry
280 * to supply the routing info.
285 /* Include the routing entry. */
286 route_reply->in_vif = gt_notify->gt_route->rt_parent;
287 if (BIT_TST(flags,RSRR_NOTIFICATION_BIT))
288 route_reply->out_vif_bm = gt_notify->gt_grpmems;
290 route_reply->out_vif_bm = 0;
291 } else if (find_src_grp(route_query->source_addr.s_addr, 0,
292 route_query->dest_addr.s_addr)) {
294 /* Found kernel entry. Code taken from add_table_entry() */
295 gt = gtp ? gtp->gt_gnext : kernel_table;
297 /* Include the routing entry. */
298 route_reply->in_vif = gt->gt_route->rt_parent;
299 route_reply->out_vif_bm = gt->gt_grpmems;
301 /* Cache reply if using route change notification. */
302 if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
303 rsrr_cache(gt,route_query);
304 BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
308 /* No kernel entry; use routing table. */
309 r = determine_route(route_query->source_addr.s_addr);
312 /* We need to mimic what will happen if a data packet
313 * is forwarded by multicast routing -- the kernel will
314 * make an upcall and mrouted will install a route in the kernel.
315 * Our outgoing vif bitmap should reflect what that table
316 * will look like. Grab code from add_table_entry().
317 * This is gross, but it's probably better to be accurate.
321 mcastgrp = route_query->dest_addr.s_addr;
323 gt->gt_mcastgrp = mcastgrp;
328 /* obtain the multicast group membership list */
329 determine_forwvifs(gt);
331 /* Include the routing entry. */
332 route_reply->in_vif = gt->gt_route->rt_parent;
333 route_reply->out_vif_bm = gt->gt_grpmems;
337 BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
342 log(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
343 gt_notify ? "Route Change: " : "",
344 inet_fmt(route_reply->source_addr.s_addr,s1),
345 inet_fmt(route_reply->dest_addr.s_addr,s2),
346 route_reply->in_vif,route_reply->out_vif_bm);
349 return rsrr_send(sendlen);
352 /* Send an RSRR message. */
360 error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
361 (struct sockaddr *)&client_addr, client_length);
363 /* Check for errors. */
365 log(LOG_WARNING, errno, "Failed send on RSRR socket");
366 } else if (error != sendlen) {
368 "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
373 /* Cache a message being sent to a client. Currently only used for
374 * caching Route Reply messages for route change notification.
377 rsrr_cache(gt,route_query)
379 struct rsrr_rq *route_query;
381 struct rsrr_cache *rc, **rcnp;
382 struct rsrr_header *rsrr;
384 rsrr = (struct rsrr_header *) rsrr_send_buf;
386 rcnp = >->gt_rsrr_cache;
387 while ((rc = *rcnp) != NULL) {
388 if ((rc->route_query.source_addr.s_addr ==
389 route_query->source_addr.s_addr) &&
390 (rc->route_query.dest_addr.s_addr ==
391 route_query->dest_addr.s_addr) &&
392 (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
393 /* Cache entry already exists.
394 * Check if route notification bit has been cleared.
396 if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
397 /* Delete cache entry. */
402 rc->route_query.query_id = route_query->query_id;
405 "Update cached query id %ld from client %s\n",
406 rc->route_query.query_id, rc->client_addr.sun_path);
413 /* Cache entry doesn't already exist. Create one and insert at
416 rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
418 log(LOG_ERR, 0, "ran out of memory");
419 rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
420 rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
421 rc->route_query.query_id = route_query->query_id;
422 strcpy(rc->client_addr.sun_path, client_addr.sun_path);
423 rc->client_length = client_length;
424 rc->next = gt->gt_rsrr_cache;
425 gt->gt_rsrr_cache = rc;
427 log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
428 rc->route_query.query_id,rc->client_addr.sun_path);
431 /* Send all the messages in the cache. Currently this is used to send
432 * all the cached Route Reply messages for route change notification.
435 rsrr_cache_send(gt,notify)
439 struct rsrr_cache *rc, **rcnp;
443 BIT_SET(flags,RSRR_NOTIFICATION_BIT);
445 rcnp = >->gt_rsrr_cache;
446 while ((rc = *rcnp) != NULL) {
447 if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
449 log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
450 rc->route_query.query_id,rc->client_addr.sun_path);
451 /* Delete cache entry. */
460 /* Clean the cache by deleting all entries. */
465 struct rsrr_cache *rc,*rc_next;
468 log(LOG_DEBUG, 0, "cleaning cache for group %s\n",
469 inet_fmt(gt->gt_mcastgrp, s1));
470 rc = gt->gt_rsrr_cache;
476 gt->gt_rsrr_cache = NULL;
482 unlink(RSRR_SERV_PATH);