time: Use clock_gettime
[dragonfly.git] / usr.sbin / mrouted / rsrr.c
blobc307d0a0403a2c8a3e18844a69e906f4229c8db1
1 /*
2 * Copyright (c) 1993 by the University of Southern California
3 * All rights reserved.
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.
26 * $FreeBSD: src/usr.sbin/mrouted/rsrr.c,v 1.8.2.1 2001/05/12 09:48:20 kris Exp $
29 /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
30 * April 1995.
33 /* May 1995 -- Added support for Route Change Notification */
35 #ifdef RSRR
37 #include "defs.h"
38 #include <sys/param.h>
39 #ifdef HAVE_SA_LEN
40 #include <stddef.h> /* for offsetof */
41 #endif
44 * Exported variables.
46 int rsrr_socket; /* interface to reservation protocol */
48 /*
49 * Global RSRR variables.
51 char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
52 char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
54 struct sockaddr_un client_addr;
55 int client_length = sizeof(client_addr);
59 * Procedure definitions needed internally.
61 static void rsrr_accept(int recvlen);
62 static void rsrr_accept_iq(void);
63 static int rsrr_accept_rq(struct rsrr_rq *route_query, int flags,
64 struct gtable *gt_notify);
65 static void rsrr_read(int, fd_set *);
66 static int rsrr_send(int sendlen);
67 static void rsrr_cache(struct gtable *gt,
68 struct rsrr_rq *route_query);
70 /* Initialize RSRR socket */
71 void
72 rsrr_init(void)
74 int servlen;
75 struct sockaddr_un serv_addr;
77 if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
78 dolog(LOG_ERR, errno, "Can't create RSRR socket");
80 unlink(RSRR_SERV_PATH);
81 bzero((char *) &serv_addr, sizeof(serv_addr));
82 serv_addr.sun_family = AF_UNIX;
83 strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
84 #ifdef HAVE_SA_LEN
85 servlen = offsetof(struct sockaddr_un, sun_path) +
86 strlen(serv_addr.sun_path);
87 serv_addr.sun_len = servlen;
88 #else
89 servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
90 #endif
92 if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
93 dolog(LOG_ERR, errno, "Can't bind RSRR socket");
95 if (register_input_handler(rsrr_socket, rsrr_read) < 0)
96 dolog(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
99 /* Read a message from the RSRR socket */
100 static void
101 rsrr_read(int f, fd_set *rfd)
103 int rsrr_recvlen;
105 bzero((char *) &client_addr, sizeof(client_addr));
106 rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
107 0, (struct sockaddr *)&client_addr, &client_length);
108 if (rsrr_recvlen < 0) {
109 if (errno != EINTR)
110 dolog(LOG_ERR, errno, "RSRR recvfrom");
111 return;
113 rsrr_accept(rsrr_recvlen);
116 /* Accept a message from the reservation protocol and take
117 * appropriate action.
119 static void
120 rsrr_accept(int recvlen)
122 struct rsrr_header *rsrr;
123 struct rsrr_rq *route_query;
125 if (recvlen < RSRR_HEADER_LEN) {
126 dolog(LOG_WARNING, 0,
127 "Received RSRR packet of %d bytes, which is less than min size",
128 recvlen);
129 return;
132 rsrr = (struct rsrr_header *) rsrr_recv_buf;
134 if (rsrr->version > RSRR_MAX_VERSION) {
135 dolog(LOG_WARNING, 0,
136 "Received RSRR packet version %d, which I don't understand",
137 rsrr->version);
138 return;
141 switch (rsrr->version) {
142 case 1:
143 switch (rsrr->type) {
144 case RSRR_INITIAL_QUERY:
145 /* Send Initial Reply to client */
146 IF_DEBUG(DEBUG_RSRR)
147 dolog(LOG_DEBUG, 0, "Received Initial Query\n");
148 rsrr_accept_iq();
149 break;
150 case RSRR_ROUTE_QUERY:
151 /* Check size */
152 if (recvlen < RSRR_RQ_LEN) {
153 dolog(LOG_WARNING, 0,
154 "Received Route Query of %d bytes, which is too small",
155 recvlen);
156 break;
158 /* Get the query */
159 route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
160 IF_DEBUG(DEBUG_RSRR)
161 dolog(LOG_DEBUG, 0,
162 "Received Route Query for src %s grp %s notification %d",
163 inet_fmt(route_query->source_addr.s_addr, s1),
164 inet_fmt(route_query->dest_addr.s_addr,s2),
165 BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
166 /* Send Route Reply to client */
167 rsrr_accept_rq(route_query,rsrr->flags,NULL);
168 break;
169 default:
170 dolog(LOG_WARNING, 0,
171 "Received RSRR packet type %d, which I don't handle",
172 rsrr->type);
173 break;
175 break;
177 default:
178 dolog(LOG_WARNING, 0,
179 "Received RSRR packet version %d, which I don't understand",
180 rsrr->version);
181 break;
185 /* Send an Initial Reply to the reservation protocol. */
186 static void
187 rsrr_accept_iq(void)
189 struct rsrr_header *rsrr;
190 struct rsrr_vif *vif_list;
191 struct uvif *v;
192 int vifi, sendlen;
194 /* Check for space. There should be room for plenty of vifs,
195 * but we should check anyway.
197 if (numvifs > RSRR_MAX_VIFS) {
198 dolog(LOG_WARNING, 0,
199 "Can't send RSRR Route Reply because %d is too many vifs",
200 numvifs);
201 return;
204 /* Set up message */
205 rsrr = (struct rsrr_header *) rsrr_send_buf;
206 rsrr->version = 1;
207 rsrr->type = RSRR_INITIAL_REPLY;
208 rsrr->flags = 0;
209 rsrr->num = numvifs;
211 vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
213 /* Include the vif list. */
214 for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
215 vif_list[vifi].id = vifi;
216 vif_list[vifi].status = 0;
217 if (v->uv_flags & VIFF_DISABLED)
218 BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
219 vif_list[vifi].threshold = v->uv_threshold;
220 vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
223 /* Get the size. */
224 sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
226 /* Send it. */
227 IF_DEBUG(DEBUG_RSRR)
228 dolog(LOG_DEBUG, 0, "Send RSRR Initial Reply");
229 rsrr_send(sendlen);
232 /* Send a Route Reply to the reservation protocol. The Route Query
233 * contains the query to which we are responding. The flags contain
234 * the incoming flags from the query or, for route change
235 * notification, the flags that should be set for the reply. The
236 * kernel table entry contains the routing info to use for a route
237 * change notification.
239 static int
240 rsrr_accept_rq(struct rsrr_rq *route_query, int flags, struct gtable *gt_notify)
242 struct rsrr_header *rsrr;
243 struct rsrr_rr *route_reply;
244 struct gtable *gt,local_g;
245 struct rtentry *r;
246 int sendlen;
247 u_long mcastgrp;
249 /* Set up message */
250 rsrr = (struct rsrr_header *) rsrr_send_buf;
251 rsrr->version = 1;
252 rsrr->type = RSRR_ROUTE_REPLY;
253 rsrr->flags = 0;
254 rsrr->num = 0;
256 route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
257 route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
258 route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
259 route_reply->query_id = route_query->query_id;
261 /* Blank routing entry for error. */
262 route_reply->in_vif = 0;
263 route_reply->reserved = 0;
264 route_reply->out_vif_bm = 0;
266 /* Get the size. */
267 sendlen = RSRR_RR_LEN;
269 /* If kernel table entry is defined, then we are sending a Route Reply
270 * due to a Route Change Notification event. Use the kernel table entry
271 * to supply the routing info.
273 if (gt_notify) {
274 /* Set flags */
275 rsrr->flags = flags;
276 /* Include the routing entry. */
277 route_reply->in_vif = gt_notify->gt_route->rt_parent;
278 if (BIT_TST(flags,RSRR_NOTIFICATION_BIT))
279 route_reply->out_vif_bm = gt_notify->gt_grpmems;
280 else
281 route_reply->out_vif_bm = 0;
282 } else if (find_src_grp(route_query->source_addr.s_addr, 0,
283 route_query->dest_addr.s_addr)) {
285 /* Found kernel entry. Code taken from add_table_entry() */
286 gt = gtp ? gtp->gt_gnext : kernel_table;
288 /* Include the routing entry. */
289 route_reply->in_vif = gt->gt_route->rt_parent;
290 route_reply->out_vif_bm = gt->gt_grpmems;
292 /* Cache reply if using route change notification. */
293 if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
294 rsrr_cache(gt,route_query);
295 BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
298 } else {
299 /* No kernel entry; use routing table. */
300 r = determine_route(route_query->source_addr.s_addr);
302 if (r != NULL) {
303 /* We need to mimic what will happen if a data packet
304 * is forwarded by multicast routing -- the kernel will
305 * make an upcall and mrouted will install a route in the kernel.
306 * Our outgoing vif bitmap should reflect what that table
307 * will look like. Grab code from add_table_entry().
308 * This is gross, but it's probably better to be accurate.
311 gt = &local_g;
312 mcastgrp = route_query->dest_addr.s_addr;
314 gt->gt_mcastgrp = mcastgrp;
315 gt->gt_grpmems = 0;
316 gt->gt_scope = 0;
317 gt->gt_route = r;
319 /* obtain the multicast group membership list */
320 determine_forwvifs(gt);
322 /* Include the routing entry. */
323 route_reply->in_vif = gt->gt_route->rt_parent;
324 route_reply->out_vif_bm = gt->gt_grpmems;
326 } else {
327 /* Set error bit. */
328 BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
332 IF_DEBUG(DEBUG_RSRR)
333 dolog(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %lu\n",
334 gt_notify ? "Route Change: " : "",
335 inet_fmt(route_reply->source_addr.s_addr,s1),
336 inet_fmt(route_reply->dest_addr.s_addr,s2),
337 route_reply->in_vif,route_reply->out_vif_bm);
339 /* Send it. */
340 return rsrr_send(sendlen);
343 /* Send an RSRR message. */
344 static int
345 rsrr_send(int sendlen)
347 int error;
349 /* Send it. */
350 error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
351 (struct sockaddr *)&client_addr, client_length);
353 /* Check for errors. */
354 if (error < 0) {
355 dolog(LOG_WARNING, errno, "Failed send on RSRR socket");
356 } else if (error != sendlen) {
357 dolog(LOG_WARNING, 0,
358 "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
360 return error;
363 /* Cache a message being sent to a client. Currently only used for
364 * caching Route Reply messages for route change notification.
366 static void
367 rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
369 struct rsrr_cache *rc, **rcnp;
370 struct rsrr_header *rsrr;
372 rsrr = (struct rsrr_header *) rsrr_send_buf;
374 rcnp = &gt->gt_rsrr_cache;
375 while ((rc = *rcnp) != NULL) {
376 if ((rc->route_query.source_addr.s_addr ==
377 route_query->source_addr.s_addr) &&
378 (rc->route_query.dest_addr.s_addr ==
379 route_query->dest_addr.s_addr) &&
380 (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
381 /* Cache entry already exists.
382 * Check if route notification bit has been cleared.
384 if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
385 /* Delete cache entry. */
386 *rcnp = rc->next;
387 free(rc);
388 } else {
389 /* Update */
390 rc->route_query.query_id = route_query->query_id;
391 IF_DEBUG(DEBUG_RSRR)
392 dolog(LOG_DEBUG, 0,
393 "Update cached query id %ld from client %s\n",
394 rc->route_query.query_id, rc->client_addr.sun_path);
396 return;
398 rcnp = &rc->next;
401 /* Cache entry doesn't already exist. Create one and insert at
402 * front of list.
404 rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
405 if (rc == NULL)
406 dolog(LOG_ERR, 0, "ran out of memory");
407 rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
408 rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_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->gt_rsrr_cache;
413 gt->gt_rsrr_cache = rc;
414 IF_DEBUG(DEBUG_RSRR)
415 dolog(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
416 rc->route_query.query_id,rc->client_addr.sun_path);
419 /* Send all the messages in the cache. Currently this is used to send
420 * all the cached Route Reply messages for route change notification.
422 void
423 rsrr_cache_send(struct gtable *gt, int notify)
425 struct rsrr_cache *rc, **rcnp;
426 int flags = 0;
428 if (notify)
429 BIT_SET(flags,RSRR_NOTIFICATION_BIT);
431 rcnp = &gt->gt_rsrr_cache;
432 while ((rc = *rcnp) != NULL) {
433 if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
434 IF_DEBUG(DEBUG_RSRR)
435 dolog(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
436 rc->route_query.query_id,rc->client_addr.sun_path);
437 /* Delete cache entry. */
438 *rcnp = rc->next;
439 free(rc);
440 } else {
441 rcnp = &rc->next;
446 /* Clean the cache by deleting all entries. */
447 void
448 rsrr_cache_clean(struct gtable *gt)
450 struct rsrr_cache *rc, *rc_next;
452 IF_DEBUG(DEBUG_RSRR)
453 dolog(LOG_DEBUG, 0, "cleaning cache for group %s\n",
454 inet_fmt(gt->gt_mcastgrp, s1));
455 rc = gt->gt_rsrr_cache;
456 while (rc) {
457 rc_next = rc->next;
458 free(rc);
459 rc = rc_next;
461 gt->gt_rsrr_cache = NULL;
464 void
465 rsrr_clean(void)
467 unlink(RSRR_SERV_PATH);
470 #endif /* RSRR */