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.
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,
33 /* May 1995 -- Added support for Route Change Notification */
38 #include <sys/param.h>
40 #include <stddef.h> /* for offsetof */
46 int rsrr_socket
; /* interface to reservation protocol */
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 */
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
);
85 servlen
= offsetof(struct sockaddr_un
, sun_path
) +
86 strlen(serv_addr
.sun_path
);
87 serv_addr
.sun_len
= servlen
;
89 servlen
= sizeof(serv_addr
.sun_family
) + strlen(serv_addr
.sun_path
);
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 */
101 rsrr_read(int f
, fd_set
*rfd
)
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) {
110 dolog(LOG_ERR
, errno
, "RSRR recvfrom");
113 rsrr_accept(rsrr_recvlen
);
116 /* Accept a message from the reservation protocol and take
117 * appropriate action.
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",
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",
141 switch (rsrr
->version
) {
143 switch (rsrr
->type
) {
144 case RSRR_INITIAL_QUERY
:
145 /* Send Initial Reply to client */
147 dolog(LOG_DEBUG
, 0, "Received Initial Query\n");
150 case RSRR_ROUTE_QUERY
:
152 if (recvlen
< RSRR_RQ_LEN
) {
153 dolog(LOG_WARNING
, 0,
154 "Received Route Query of %d bytes, which is too small",
159 route_query
= (struct rsrr_rq
*) (rsrr_recv_buf
+ RSRR_HEADER_LEN
);
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
);
170 dolog(LOG_WARNING
, 0,
171 "Received RSRR packet type %d, which I don't handle",
178 dolog(LOG_WARNING
, 0,
179 "Received RSRR packet version %d, which I don't understand",
185 /* Send an Initial Reply to the reservation protocol. */
189 struct rsrr_header
*rsrr
;
190 struct rsrr_vif
*vif_list
;
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",
205 rsrr
= (struct rsrr_header
*) rsrr_send_buf
;
207 rsrr
->type
= RSRR_INITIAL_REPLY
;
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
;
224 sendlen
= RSRR_HEADER_LEN
+ numvifs
*RSRR_VIF_LEN
;
228 dolog(LOG_DEBUG
, 0, "Send RSRR Initial Reply");
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.
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
;
250 rsrr
= (struct rsrr_header
*) rsrr_send_buf
;
252 rsrr
->type
= RSRR_ROUTE_REPLY
;
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;
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.
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
;
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
);
299 /* No kernel entry; use routing table. */
300 r
= determine_route(route_query
->source_addr
.s_addr
);
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.
312 mcastgrp
= route_query
->dest_addr
.s_addr
;
314 gt
->gt_mcastgrp
= mcastgrp
;
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
;
328 BIT_SET(rsrr
->flags
,RSRR_ERROR_BIT
);
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
);
340 return rsrr_send(sendlen
);
343 /* Send an RSRR message. */
345 rsrr_send(int sendlen
)
350 error
= sendto(rsrr_socket
, rsrr_send_buf
, sendlen
, 0,
351 (struct sockaddr
*)&client_addr
, client_length
);
353 /* Check for errors. */
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
);
363 /* Cache a message being sent to a client. Currently only used for
364 * caching Route Reply messages for route change notification.
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_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. */
390 rc
->route_query
.query_id
= route_query
->query_id
;
393 "Update cached query id %ld from client %s\n",
394 rc
->route_query
.query_id
, rc
->client_addr
.sun_path
);
401 /* Cache entry doesn't already exist. Create one and insert at
404 rc
= (struct rsrr_cache
*) malloc(sizeof(struct rsrr_cache
));
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
;
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.
423 rsrr_cache_send(struct gtable
*gt
, int notify
)
425 struct rsrr_cache
*rc
, **rcnp
;
429 BIT_SET(flags
,RSRR_NOTIFICATION_BIT
);
431 rcnp
= >
->gt_rsrr_cache
;
432 while ((rc
= *rcnp
) != NULL
) {
433 if (rsrr_accept_rq(&rc
->route_query
,flags
,gt
) < 0) {
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. */
446 /* Clean the cache by deleting all entries. */
448 rsrr_cache_clean(struct gtable
*gt
)
450 struct rsrr_cache
*rc
, *rc_next
;
453 dolog(LOG_DEBUG
, 0, "cleaning cache for group %s\n",
454 inet_fmt(gt
->gt_mcastgrp
, s1
));
455 rc
= gt
->gt_rsrr_cache
;
461 gt
->gt_rsrr_cache
= NULL
;
467 unlink(RSRR_SERV_PATH
);