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