1 1.13 lukem /* $NetBSD: route.c,v 1.13 2009/04/17 16:05:43 lukem Exp $ */ 2 1.4 thorpej 3 1.1 brezak /* 4 1.1 brezak * The mrouted program is covered by the license in the accompanying file 5 1.1 brezak * named "LICENSE". Use of the mrouted program represents acceptance of 6 1.1 brezak * the terms and conditions listed in that file. 7 1.1 brezak * 8 1.1 brezak * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 9 1.1 brezak * Leland Stanford Junior University. 10 1.1 brezak */ 11 1.1 brezak 12 1.1 brezak 13 1.1 brezak #include "defs.h" 14 1.1 brezak 15 1.1 brezak 16 1.1 brezak /* 17 1.3 mycroft * This define statement saves a lot of space later 18 1.3 mycroft */ 19 1.3 mycroft #define RT_ADDR (struct rtentry *)&routing_table 20 1.3 mycroft 21 1.3 mycroft /* 22 1.1 brezak * Exported variables. 23 1.1 brezak */ 24 1.1 brezak int routes_changed; /* 1=>some routes have changed */ 25 1.1 brezak int delay_change_reports; /* 1=>postpone change reports */ 26 1.1 brezak 27 1.1 brezak 28 1.1 brezak /* 29 1.3 mycroft * The routing table is shared with prune.c , so must not be static. 30 1.3 mycroft */ 31 1.3 mycroft struct rtentry *routing_table; /* pointer to list of route entries */ 32 1.3 mycroft 33 1.3 mycroft /* 34 1.1 brezak * Private variables. 35 1.1 brezak */ 36 1.1 brezak static struct rtentry *rtp; /* pointer to a route entry */ 37 1.3 mycroft static struct rtentry *rt_end; /* pointer to last route entry */ 38 1.3 mycroft unsigned int nroutes; /* current number of route entries */ 39 1.1 brezak 40 1.1 brezak /* 41 1.5 mycroft * Private functions. 42 1.5 mycroft */ 43 1.7 wiz static int init_children_and_leaves(struct rtentry *r, vifi_t parent); 44 1.7 wiz static int find_route(u_int32_t origin, u_int32_t mask); 45 1.7 wiz static void create_route(u_int32_t origin, u_int32_t mask); 46 1.7 wiz static void discard_route(struct rtentry *prev_r); 47 1.7 wiz static int compare_rts(const void *rt1, const void *rt2); 48 1.7 wiz static int report_chunk(struct rtentry *start_rt, vifi_t vifi, u_int32_t dst); 49 1.5 mycroft 50 1.5 mycroft /* 51 1.1 brezak * Initialize the routing table and associated variables. 52 1.1 brezak */ 53 1.3 mycroft void 54 1.7 wiz init_routes(void) 55 1.1 brezak { 56 1.1 brezak routing_table = NULL; 57 1.5 mycroft rt_end = RT_ADDR; 58 1.1 brezak nroutes = 0; 59 1.1 brezak routes_changed = FALSE; 60 1.1 brezak delay_change_reports = FALSE; 61 1.1 brezak } 62 1.1 brezak 63 1.1 brezak 64 1.1 brezak /* 65 1.1 brezak * Initialize the children and leaf bits for route 'r', along with the 66 1.1 brezak * associated dominant, subordinate, and leaf timing data structures. 67 1.1 brezak * Return TRUE if this changes the value of either the children or 68 1.1 brezak * leaf bitmaps for 'r'. 69 1.1 brezak */ 70 1.3 mycroft static int 71 1.7 wiz init_children_and_leaves(struct rtentry *r, vifi_t parent) 72 1.1 brezak { 73 1.7 wiz vifi_t vifi; 74 1.7 wiz struct uvif *v; 75 1.1 brezak vifbitmap_t old_children, old_leaves; 76 1.1 brezak 77 1.1 brezak VIFM_COPY(r->rt_children, old_children); 78 1.1 brezak VIFM_COPY(r->rt_leaves, old_leaves ); 79 1.1 brezak 80 1.1 brezak VIFM_CLRALL(r->rt_children); 81 1.1 brezak VIFM_CLRALL(r->rt_leaves); 82 1.1 brezak r->rt_flags &= ~RTF_LEAF_TIMING; 83 1.1 brezak 84 1.1 brezak for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { 85 1.1 brezak r->rt_dominants [vifi] = 0; 86 1.1 brezak r->rt_subordinates[vifi] = 0; 87 1.1 brezak 88 1.1 brezak if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) { 89 1.1 brezak VIFM_SET(vifi, r->rt_children); 90 1.1 brezak if (v->uv_neighbors == NULL) { 91 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 92 1.1 brezak r->rt_leaf_timers[vifi] = 0; 93 1.1 brezak } 94 1.1 brezak else { 95 1.1 brezak r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; 96 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 97 1.1 brezak } 98 1.1 brezak } 99 1.1 brezak else { 100 1.1 brezak r->rt_leaf_timers[vifi] = 0; 101 1.1 brezak } 102 1.1 brezak } 103 1.1 brezak 104 1.1 brezak return (!VIFM_SAME(r->rt_children, old_children) || 105 1.1 brezak !VIFM_SAME(r->rt_leaves, old_leaves)); 106 1.1 brezak } 107 1.1 brezak 108 1.1 brezak 109 1.1 brezak /* 110 1.1 brezak * A new vif has come up -- update the children and leaf bitmaps in all route 111 1.1 brezak * entries to take that into account. 112 1.1 brezak */ 113 1.3 mycroft void 114 1.7 wiz add_vif_to_routes(vifi_t vifi) 115 1.1 brezak { 116 1.7 wiz struct rtentry *r; 117 1.7 wiz struct uvif *v; 118 1.1 brezak 119 1.1 brezak v = &uvifs[vifi]; 120 1.1 brezak for (r = routing_table; r != NULL; r = r->rt_next) { 121 1.1 brezak if (r->rt_metric != UNREACHABLE && 122 1.1 brezak !VIFM_ISSET(vifi, r->rt_children)) { 123 1.1 brezak VIFM_SET(vifi, r->rt_children); 124 1.1 brezak r->rt_dominants [vifi] = 0; 125 1.1 brezak r->rt_subordinates[vifi] = 0; 126 1.1 brezak if (v->uv_neighbors == NULL) { 127 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 128 1.1 brezak r->rt_leaf_timers[vifi] = 0; 129 1.1 brezak } 130 1.1 brezak else { 131 1.1 brezak VIFM_CLR(vifi, r->rt_leaves); 132 1.1 brezak r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; 133 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 134 1.1 brezak } 135 1.3 mycroft update_table_entry(r); 136 1.1 brezak } 137 1.1 brezak } 138 1.1 brezak } 139 1.1 brezak 140 1.1 brezak 141 1.1 brezak /* 142 1.1 brezak * A vif has gone down -- expire all routes that have that vif as parent, 143 1.1 brezak * and update the children bitmaps in all other route entries to take into 144 1.1 brezak * account the failed vif. 145 1.1 brezak */ 146 1.3 mycroft void 147 1.7 wiz delete_vif_from_routes(vifi_t vifi) 148 1.1 brezak { 149 1.7 wiz struct rtentry *r; 150 1.1 brezak 151 1.1 brezak for (r = routing_table; r != NULL; r = r->rt_next) { 152 1.1 brezak if (r->rt_metric != UNREACHABLE) { 153 1.1 brezak if (vifi == r->rt_parent) { 154 1.3 mycroft del_table_entry(r, 0, DEL_ALL_ROUTES); 155 1.1 brezak r->rt_timer = ROUTE_EXPIRE_TIME; 156 1.1 brezak r->rt_metric = UNREACHABLE; 157 1.1 brezak r->rt_flags |= RTF_CHANGED; 158 1.1 brezak routes_changed = TRUE; 159 1.1 brezak } 160 1.1 brezak else if (VIFM_ISSET(vifi, r->rt_children)) { 161 1.1 brezak VIFM_CLR(vifi, r->rt_children); 162 1.1 brezak VIFM_CLR(vifi, r->rt_leaves); 163 1.1 brezak r->rt_subordinates[vifi] = 0; 164 1.1 brezak r->rt_leaf_timers [vifi] = 0; 165 1.3 mycroft update_table_entry(r); 166 1.1 brezak } 167 1.1 brezak else { 168 1.1 brezak r->rt_dominants[vifi] = 0; 169 1.1 brezak } 170 1.1 brezak } 171 1.1 brezak } 172 1.1 brezak } 173 1.1 brezak 174 1.1 brezak 175 1.1 brezak /* 176 1.1 brezak * A neighbor has failed or become unreachable. If that neighbor was 177 1.1 brezak * considered a dominant or subordinate router in any route entries, 178 1.1 brezak * take appropriate action. 179 1.1 brezak */ 180 1.3 mycroft void 181 1.7 wiz delete_neighbor_from_routes(u_int32_t addr, vifi_t vifi) 182 1.1 brezak { 183 1.7 wiz struct rtentry *r; 184 1.7 wiz struct uvif *v; 185 1.1 brezak 186 1.1 brezak v = &uvifs[vifi]; 187 1.1 brezak for (r = routing_table; r != NULL; r = r->rt_next) { 188 1.1 brezak if (r->rt_metric != UNREACHABLE) { 189 1.1 brezak if (r->rt_dominants[vifi] == addr) { 190 1.1 brezak VIFM_SET(vifi, r->rt_children); 191 1.1 brezak r->rt_dominants [vifi] = 0; 192 1.1 brezak r->rt_subordinates[vifi] = 0; 193 1.1 brezak if (v->uv_neighbors == NULL) { 194 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 195 1.1 brezak r->rt_leaf_timers[vifi] = 0; 196 1.1 brezak } 197 1.1 brezak else { 198 1.1 brezak VIFM_CLR(vifi, r->rt_leaves); 199 1.1 brezak r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; 200 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 201 1.1 brezak } 202 1.3 mycroft update_table_entry(r); 203 1.1 brezak } 204 1.1 brezak else if (r->rt_subordinates[vifi] == addr) { 205 1.1 brezak r->rt_subordinates[vifi] = 0; 206 1.1 brezak if (v->uv_neighbors == NULL) { 207 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 208 1.3 mycroft update_table_entry(r); 209 1.1 brezak } 210 1.1 brezak else { 211 1.1 brezak r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; 212 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 213 1.1 brezak } 214 1.1 brezak } 215 1.1 brezak else if (v->uv_neighbors == NULL && 216 1.1 brezak r->rt_leaf_timers[vifi] != 0) { 217 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 218 1.1 brezak r->rt_leaf_timers[vifi] = 0; 219 1.3 mycroft update_table_entry(r); 220 1.1 brezak } 221 1.1 brezak } 222 1.1 brezak } 223 1.1 brezak } 224 1.1 brezak 225 1.1 brezak 226 1.1 brezak /* 227 1.1 brezak * Prepare for a sequence of ordered route updates by initializing a pointer 228 1.1 brezak * to the start of the routing table. The pointer is used to remember our 229 1.1 brezak * position in the routing table in order to avoid searching from the 230 1.1 brezak * beginning for each update; this relies on having the route reports in 231 1.1 brezak * a single message be in the same order as the route entries in the routing 232 1.1 brezak * table. 233 1.1 brezak */ 234 1.3 mycroft void 235 1.7 wiz start_route_updates(void) 236 1.1 brezak { 237 1.3 mycroft rtp = RT_ADDR; 238 1.1 brezak } 239 1.1 brezak 240 1.1 brezak 241 1.1 brezak /* 242 1.1 brezak * Starting at the route entry following the one to which 'rtp' points, 243 1.1 brezak * look for a route entry matching the specified origin and mask. If a 244 1.1 brezak * match is found, return TRUE and leave 'rtp' pointing at the found entry. 245 1.1 brezak * If no match is found, return FALSE and leave 'rtp' pointing to the route 246 1.1 brezak * entry preceding the point at which the new origin should be inserted. 247 1.1 brezak * This code is optimized for the normal case in which the first entry to 248 1.1 brezak * be examined is the matching entry. 249 1.1 brezak */ 250 1.3 mycroft static int 251 1.7 wiz find_route(u_int32_t origin, u_int32_t mask) 252 1.1 brezak { 253 1.7 wiz struct rtentry *r; 254 1.1 brezak 255 1.1 brezak r = rtp->rt_next; 256 1.1 brezak while (r != NULL) { 257 1.1 brezak if (origin == r->rt_origin && mask == r->rt_originmask) { 258 1.1 brezak rtp = r; 259 1.1 brezak return (TRUE); 260 1.1 brezak } 261 1.3 mycroft if (ntohl(mask) < ntohl(r->rt_originmask) || 262 1.1 brezak (mask == r->rt_originmask && 263 1.3 mycroft ntohl(origin) < ntohl(r->rt_origin))) { 264 1.1 brezak rtp = r; 265 1.1 brezak r = r->rt_next; 266 1.1 brezak } 267 1.1 brezak else break; 268 1.1 brezak } 269 1.1 brezak return (FALSE); 270 1.1 brezak } 271 1.1 brezak 272 1.1 brezak /* 273 1.1 brezak * Create a new routing table entry for the specified origin and link it into 274 1.1 brezak * the routing table. The shared variable 'rtp' is assumed to point to the 275 1.1 brezak * routing entry after which the new one should be inserted. It is left 276 1.1 brezak * pointing to the new entry. 277 1.1 brezak * 278 1.1 brezak * Only the origin, originmask, originwidth and flags fields are initialized 279 1.6 soren * in the new route entry; the caller is responsible for filling in the rest. 280 1.1 brezak */ 281 1.3 mycroft static void 282 1.7 wiz create_route(u_int32_t origin, u_int32_t mask) 283 1.1 brezak { 284 1.7 wiz struct rtentry *r; 285 1.1 brezak 286 1.3 mycroft if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) + 287 1.3 mycroft (2 * numvifs * sizeof(u_int32_t)) + 288 1.5 mycroft (numvifs * sizeof(u_int)))) == NULL) { 289 1.9 wiz logit(LOG_ERR, 0, "ran out of memory"); /* fatal */ 290 1.12 christos return; 291 1.1 brezak } 292 1.1 brezak r->rt_origin = origin; 293 1.1 brezak r->rt_originmask = mask; 294 1.1 brezak if (((char *)&mask)[3] != 0) r->rt_originwidth = 4; 295 1.1 brezak else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3; 296 1.1 brezak else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2; 297 1.1 brezak else r->rt_originwidth = 1; 298 1.1 brezak r->rt_flags = 0; 299 1.3 mycroft r->rt_dominants = (u_int32_t *)(r + 1); 300 1.3 mycroft r->rt_subordinates = (u_int32_t *)(r->rt_dominants + numvifs); 301 1.5 mycroft r->rt_leaf_timers = (u_int *)(r->rt_subordinates + numvifs); 302 1.3 mycroft r->rt_groups = NULL; 303 1.1 brezak 304 1.1 brezak r->rt_next = rtp->rt_next; 305 1.1 brezak rtp->rt_next = r; 306 1.3 mycroft r->rt_prev = rtp; 307 1.3 mycroft if (r->rt_next != NULL) 308 1.3 mycroft (r->rt_next)->rt_prev = r; 309 1.3 mycroft else 310 1.3 mycroft rt_end = r; 311 1.1 brezak rtp = r; 312 1.1 brezak ++nroutes; 313 1.1 brezak } 314 1.1 brezak 315 1.1 brezak 316 1.1 brezak /* 317 1.1 brezak * Discard the routing table entry following the one to which 'prev_r' points. 318 1.1 brezak */ 319 1.3 mycroft static void 320 1.7 wiz discard_route(struct rtentry *prev_r) 321 1.1 brezak { 322 1.7 wiz struct rtentry *r; 323 1.1 brezak 324 1.1 brezak r = prev_r->rt_next; 325 1.1 brezak prev_r->rt_next = r->rt_next; 326 1.3 mycroft if (prev_r->rt_next != NULL) 327 1.3 mycroft (prev_r->rt_next)->rt_prev = prev_r; 328 1.3 mycroft else 329 1.3 mycroft rt_end = prev_r; 330 1.1 brezak free((char *)r); 331 1.1 brezak --nroutes; 332 1.1 brezak } 333 1.1 brezak 334 1.1 brezak 335 1.1 brezak /* 336 1.1 brezak * Process a route report for a single origin, creating or updating the 337 1.1 brezak * corresponding routing table entry if necessary. 'src' is either the 338 1.1 brezak * address of a neighboring router from which the report arrived, or zero 339 1.1 brezak * to indicate a change of status of one of our own interfaces. 340 1.1 brezak */ 341 1.3 mycroft void 342 1.7 wiz update_route(u_int32_t origin, u_int32_t mask, u_int metric, u_int32_t src, 343 1.7 wiz vifi_t vifi) 344 1.1 brezak { 345 1.7 wiz struct rtentry *r; 346 1.5 mycroft u_int adj_metric; 347 1.1 brezak 348 1.1 brezak /* 349 1.1 brezak * Compute an adjusted metric, taking into account the cost of the 350 1.1 brezak * subnet or tunnel over which the report arrived, and normalizing 351 1.1 brezak * all unreachable/poisoned metrics into a single value. 352 1.1 brezak */ 353 1.1 brezak if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) { 354 1.9 wiz logit(LOG_WARNING, 0, 355 1.1 brezak "%s reports out-of-range metric %u for origin %s", 356 1.11 dsl inet_fmt(src), metric, 357 1.11 dsl inet_fmts(origin, mask)); 358 1.1 brezak return; 359 1.1 brezak } 360 1.1 brezak adj_metric = metric + uvifs[vifi].uv_metric; 361 1.1 brezak if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE; 362 1.1 brezak 363 1.1 brezak /* 364 1.1 brezak * Look up the reported origin in the routing table. 365 1.1 brezak */ 366 1.1 brezak if (!find_route(origin, mask)) { 367 1.1 brezak /* 368 1.1 brezak * Not found. 369 1.1 brezak * Don't create a new entry if the report says it's unreachable, 370 1.1 brezak * or if the reported origin and mask are invalid. 371 1.1 brezak */ 372 1.1 brezak if (adj_metric == UNREACHABLE) { 373 1.1 brezak return; 374 1.1 brezak } 375 1.1 brezak if (src != 0 && !inet_valid_subnet(origin, mask)) { 376 1.9 wiz logit(LOG_WARNING, 0, 377 1.1 brezak "%s reports an invalid origin (%s) and/or mask (%08x)", 378 1.11 dsl inet_fmt(src), 379 1.11 dsl inet_fmt(origin), ntohl(mask)); 380 1.1 brezak return; 381 1.1 brezak } 382 1.1 brezak 383 1.1 brezak /* 384 1.3 mycroft * OK, create the new routing entry. 'rtp' will be left pointing 385 1.3 mycroft * to the new entry. 386 1.1 brezak */ 387 1.3 mycroft create_route(origin, mask); 388 1.1 brezak 389 1.1 brezak /* 390 1.3 mycroft * Now "steal away" any sources that belong under this route 391 1.3 mycroft * by deleting any cache entries they might have created 392 1.3 mycroft * and allowing the kernel to re-request them. 393 1.1 brezak */ 394 1.3 mycroft steal_sources(rtp); 395 1.1 brezak 396 1.1 brezak rtp->rt_metric = UNREACHABLE; /* temporary; updated below */ 397 1.1 brezak } 398 1.1 brezak 399 1.1 brezak /* 400 1.1 brezak * We now have a routing entry for the reported origin. Update it? 401 1.1 brezak */ 402 1.1 brezak r = rtp; 403 1.1 brezak if (r->rt_metric == UNREACHABLE) { 404 1.1 brezak /* 405 1.1 brezak * The routing entry is for a formerly-unreachable or new origin. 406 1.1 brezak * If the report claims reachability, update the entry to use 407 1.1 brezak * the reported route. 408 1.1 brezak */ 409 1.1 brezak if (adj_metric == UNREACHABLE) 410 1.1 brezak return; 411 1.1 brezak 412 1.1 brezak r->rt_parent = vifi; 413 1.1 brezak init_children_and_leaves(r, vifi); 414 1.3 mycroft 415 1.1 brezak r->rt_gateway = src; 416 1.1 brezak r->rt_timer = 0; 417 1.1 brezak r->rt_metric = adj_metric; 418 1.1 brezak r->rt_flags |= RTF_CHANGED; 419 1.1 brezak routes_changed = TRUE; 420 1.3 mycroft update_table_entry(r); 421 1.1 brezak } 422 1.1 brezak else if (src == r->rt_gateway) { 423 1.1 brezak /* 424 1.1 brezak * The report has come either from the interface directly-connected 425 1.1 brezak * to the origin subnet (src and r->rt_gateway both equal zero) or 426 1.1 brezak * from the gateway we have chosen as the best first-hop gateway back 427 1.1 brezak * towards the origin (src and r->rt_gateway not equal zero). Reset 428 1.1 brezak * the route timer and, if the reported metric has changed, update 429 1.1 brezak * our entry accordingly. 430 1.1 brezak */ 431 1.1 brezak r->rt_timer = 0; 432 1.1 brezak if (adj_metric == r->rt_metric) 433 1.1 brezak return; 434 1.1 brezak 435 1.1 brezak if (adj_metric == UNREACHABLE) { 436 1.3 mycroft del_table_entry(r, 0, DEL_ALL_ROUTES); 437 1.1 brezak r->rt_timer = ROUTE_EXPIRE_TIME; 438 1.1 brezak } 439 1.1 brezak else if (adj_metric < r->rt_metric) { 440 1.1 brezak if (init_children_and_leaves(r, vifi)) { 441 1.3 mycroft update_table_entry(r); 442 1.1 brezak } 443 1.1 brezak } 444 1.1 brezak r->rt_metric = adj_metric; 445 1.1 brezak r->rt_flags |= RTF_CHANGED; 446 1.1 brezak routes_changed = TRUE; 447 1.1 brezak } 448 1.1 brezak else if (src == 0 || 449 1.3 mycroft (r->rt_gateway != 0 && 450 1.3 mycroft (adj_metric < r->rt_metric || 451 1.3 mycroft (adj_metric == r->rt_metric && 452 1.5 mycroft (ntohl(src) < ntohl(r->rt_gateway) || 453 1.5 mycroft r->rt_timer >= ROUTE_SWITCH_TIME))))) { 454 1.1 brezak /* 455 1.1 brezak * The report is for an origin we consider reachable; the report 456 1.1 brezak * comes either from one of our own interfaces or from a gateway 457 1.1 brezak * other than the one we have chosen as the best first-hop gateway 458 1.1 brezak * back towards the origin. If the source of the update is one of 459 1.1 brezak * our own interfaces, or if the origin is not a directly-connected 460 1.1 brezak * subnet and the reported metric for that origin is better than 461 1.1 brezak * what our routing entry says, update the entry to use the new 462 1.1 brezak * gateway and metric. We also switch gateways if the reported 463 1.1 brezak * metric is the same as the one in the route entry and the gateway 464 1.5 mycroft * associated with the route entry has not been heard from recently, 465 1.5 mycroft * or if the metric is the same but the reporting gateway has a lower 466 1.5 mycroft * IP address than the gateway associated with the route entry. 467 1.1 brezak * Did you get all that? 468 1.1 brezak */ 469 1.1 brezak if (r->rt_parent != vifi || adj_metric < r->rt_metric) { 470 1.5 mycroft /* 471 1.5 mycroft * XXX Why do we do this if we are just changing the metric? 472 1.5 mycroft */ 473 1.1 brezak r->rt_parent = vifi; 474 1.1 brezak if (init_children_and_leaves(r, vifi)) { 475 1.3 mycroft update_table_entry(r); 476 1.1 brezak } 477 1.1 brezak } 478 1.1 brezak r->rt_gateway = src; 479 1.1 brezak r->rt_timer = 0; 480 1.1 brezak r->rt_metric = adj_metric; 481 1.1 brezak r->rt_flags |= RTF_CHANGED; 482 1.1 brezak routes_changed = TRUE; 483 1.1 brezak } 484 1.1 brezak else if (vifi != r->rt_parent) { 485 1.1 brezak /* 486 1.1 brezak * The report came from a vif other than the route's parent vif. 487 1.1 brezak * Update the children and leaf info, if necessary. 488 1.1 brezak */ 489 1.1 brezak if (VIFM_ISSET(vifi, r->rt_children)) { 490 1.1 brezak /* 491 1.1 brezak * Vif is a child vif for this route. 492 1.1 brezak */ 493 1.1 brezak if (metric < r->rt_metric || 494 1.3 mycroft (metric == r->rt_metric && 495 1.3 mycroft ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) { 496 1.1 brezak /* 497 1.1 brezak * Neighbor has lower metric to origin (or has same metric 498 1.1 brezak * and lower IP address) -- it becomes the dominant router, 499 1.1 brezak * and vif is no longer a child for me. 500 1.1 brezak */ 501 1.1 brezak VIFM_CLR(vifi, r->rt_children); 502 1.1 brezak VIFM_CLR(vifi, r->rt_leaves); 503 1.1 brezak r->rt_dominants [vifi] = src; 504 1.1 brezak r->rt_subordinates[vifi] = 0; 505 1.1 brezak r->rt_leaf_timers [vifi] = 0; 506 1.3 mycroft update_table_entry(r); 507 1.1 brezak } 508 1.1 brezak else if (metric > UNREACHABLE) { /* "poisoned reverse" */ 509 1.1 brezak /* 510 1.1 brezak * Neighbor considers this vif to be on path to route's 511 1.1 brezak * origin; if no subordinate recorded, record this neighbor 512 1.1 brezak * as subordinate and clear the leaf flag. 513 1.1 brezak */ 514 1.1 brezak if (r->rt_subordinates[vifi] == 0) { 515 1.1 brezak VIFM_CLR(vifi, r->rt_leaves); 516 1.1 brezak r->rt_subordinates[vifi] = src; 517 1.1 brezak r->rt_leaf_timers [vifi] = 0; 518 1.3 mycroft update_table_entry(r); 519 1.1 brezak } 520 1.1 brezak } 521 1.1 brezak else if (src == r->rt_subordinates[vifi]) { 522 1.1 brezak /* 523 1.1 brezak * Current subordinate no longer considers this vif to be on 524 1.1 brezak * path to route's origin; it is no longer a subordinate 525 1.1 brezak * router, and we set the leaf confirmation timer to give 526 1.1 brezak * us time to hear from other subordinates. 527 1.1 brezak */ 528 1.1 brezak r->rt_subordinates[vifi] = 0; 529 1.1 brezak if (uvifs[vifi].uv_neighbors == NULL || 530 1.1 brezak uvifs[vifi].uv_neighbors->al_next == NULL) { 531 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 532 1.3 mycroft update_table_entry(r); 533 1.1 brezak } 534 1.1 brezak else { 535 1.1 brezak r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME; 536 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 537 1.1 brezak } 538 1.1 brezak } 539 1.1 brezak 540 1.1 brezak } 541 1.1 brezak else if (src == r->rt_dominants[vifi] && 542 1.3 mycroft (metric > r->rt_metric || 543 1.3 mycroft (metric == r->rt_metric && 544 1.3 mycroft ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) { 545 1.1 brezak /* 546 1.1 brezak * Current dominant no longer has a lower metric to origin 547 1.1 brezak * (or same metric and lower IP address); we adopt the vif 548 1.1 brezak * as our own child. 549 1.1 brezak */ 550 1.1 brezak VIFM_SET(vifi, r->rt_children); 551 1.1 brezak r->rt_dominants [vifi] = 0; 552 1.1 brezak if (metric > UNREACHABLE) { 553 1.1 brezak r->rt_subordinates[vifi] = src; 554 1.1 brezak } 555 1.1 brezak else if (uvifs[vifi].uv_neighbors == NULL || 556 1.1 brezak uvifs[vifi].uv_neighbors->al_next == NULL) { 557 1.1 brezak VIFM_SET(vifi, r->rt_leaves); 558 1.1 brezak } 559 1.1 brezak else { 560 1.1 brezak r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME; 561 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 562 1.1 brezak } 563 1.3 mycroft update_table_entry(r); 564 1.1 brezak } 565 1.1 brezak } 566 1.1 brezak } 567 1.1 brezak 568 1.1 brezak 569 1.1 brezak /* 570 1.1 brezak * On every timer interrupt, advance the timer in each routing entry. 571 1.1 brezak */ 572 1.3 mycroft void 573 1.7 wiz age_routes(void) 574 1.1 brezak { 575 1.7 wiz struct rtentry *r; 576 1.7 wiz struct rtentry *prev_r; 577 1.7 wiz vifi_t vifi; 578 1.1 brezak 579 1.3 mycroft for (prev_r = RT_ADDR, r = routing_table; 580 1.1 brezak r != NULL; 581 1.1 brezak prev_r = r, r = r->rt_next) { 582 1.1 brezak 583 1.1 brezak if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) { 584 1.1 brezak /* 585 1.1 brezak * Route is still good; see if any leaf timers need to be 586 1.1 brezak * advanced. 587 1.1 brezak */ 588 1.1 brezak if (r->rt_flags & RTF_LEAF_TIMING) { 589 1.1 brezak r->rt_flags &= ~RTF_LEAF_TIMING; 590 1.1 brezak for (vifi = 0; vifi < numvifs; ++vifi) { 591 1.1 brezak if (r->rt_leaf_timers[vifi] != 0) { 592 1.1 brezak /* 593 1.1 brezak * Unlike other timers, leaf timers decrement. 594 1.1 brezak */ 595 1.1 brezak if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){ 596 1.3 mycroft #ifdef NOTYET 597 1.3 mycroft /* If the vif is a physical leaf but has neighbors, 598 1.3 mycroft * it is not a tree leaf. If I am a leaf, then no 599 1.3 mycroft * interface with neighbors is a tree leaf. */ 600 1.3 mycroft if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) || 601 1.3 mycroft (vifs_with_neighbors == 1)) && 602 1.3 mycroft (uvifs[vifi].uv_neighbors != NULL))) { 603 1.3 mycroft #endif 604 1.3 mycroft VIFM_SET(vifi, r->rt_leaves); 605 1.3 mycroft update_table_entry(r); 606 1.3 mycroft #ifdef NOTYET 607 1.3 mycroft } 608 1.3 mycroft #endif 609 1.1 brezak } 610 1.1 brezak else { 611 1.1 brezak r->rt_flags |= RTF_LEAF_TIMING; 612 1.1 brezak } 613 1.1 brezak } 614 1.1 brezak } 615 1.1 brezak } 616 1.1 brezak } 617 1.1 brezak else if (r->rt_timer >= ROUTE_DISCARD_TIME) { 618 1.1 brezak /* 619 1.1 brezak * Time to garbage-collect the route entry. 620 1.1 brezak */ 621 1.3 mycroft del_table_entry(r, 0, DEL_ALL_ROUTES); 622 1.1 brezak discard_route(prev_r); 623 1.1 brezak r = prev_r; 624 1.1 brezak } 625 1.1 brezak else if (r->rt_metric != UNREACHABLE) { 626 1.1 brezak /* 627 1.1 brezak * Time to expire the route entry. If the gateway is zero, 628 1.1 brezak * i.e., it is a route to a directly-connected subnet, just 629 1.1 brezak * set the timer back to zero; such routes expire only when 630 1.1 brezak * the interface to the subnet goes down. 631 1.1 brezak */ 632 1.1 brezak if (r->rt_gateway == 0) { 633 1.1 brezak r->rt_timer = 0; 634 1.3 mycroft } 635 1.1 brezak else { 636 1.3 mycroft del_table_entry(r, 0, DEL_ALL_ROUTES); 637 1.1 brezak r->rt_metric = UNREACHABLE; 638 1.1 brezak r->rt_flags |= RTF_CHANGED; 639 1.1 brezak routes_changed = TRUE; 640 1.1 brezak } 641 1.1 brezak } 642 1.1 brezak } 643 1.1 brezak } 644 1.1 brezak 645 1.1 brezak 646 1.1 brezak /* 647 1.1 brezak * Mark all routes as unreachable. This function is called only from 648 1.1 brezak * hup() in preparation for informing all neighbors that we are going 649 1.1 brezak * off the air. For consistency, we ought also to delete all reachable 650 1.1 brezak * route entries from the kernel, but since we are about to exit we rely 651 1.1 brezak * on the kernel to do its own cleanup -- no point in making all those 652 1.1 brezak * expensive kernel calls now. 653 1.1 brezak */ 654 1.3 mycroft void 655 1.7 wiz expire_all_routes(void) 656 1.1 brezak { 657 1.7 wiz struct rtentry *r; 658 1.1 brezak 659 1.1 brezak for (r = routing_table; r != NULL; r = r->rt_next) { 660 1.1 brezak r->rt_metric = UNREACHABLE; 661 1.1 brezak r->rt_flags |= RTF_CHANGED; 662 1.1 brezak routes_changed = TRUE; 663 1.1 brezak } 664 1.1 brezak } 665 1.1 brezak 666 1.1 brezak 667 1.1 brezak /* 668 1.3 mycroft * Delete all the routes in the routing table. 669 1.3 mycroft */ 670 1.3 mycroft void 671 1.7 wiz free_all_routes(void) 672 1.3 mycroft { 673 1.7 wiz struct rtentry *r; 674 1.3 mycroft 675 1.3 mycroft r = RT_ADDR; 676 1.3 mycroft 677 1.3 mycroft while (r->rt_next) 678 1.3 mycroft discard_route(r); 679 1.3 mycroft } 680 1.3 mycroft 681 1.3 mycroft 682 1.3 mycroft /* 683 1.1 brezak * Process an incoming neighbor probe message. 684 1.1 brezak */ 685 1.3 mycroft void 686 1.7 wiz accept_probe(u_int32_t src, u_int32_t dst, char *p, int datalen, 687 1.7 wiz u_int32_t level) 688 1.1 brezak { 689 1.1 brezak vifi_t vifi; 690 1.1 brezak 691 1.1 brezak if ((vifi = find_vif(src, dst)) == NO_VIF) { 692 1.9 wiz logit(LOG_INFO, 0, 693 1.11 dsl "ignoring probe from non-neighbor %s", inet_fmt(src)); 694 1.1 brezak return; 695 1.1 brezak } 696 1.1 brezak 697 1.5 mycroft update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level); 698 1.1 brezak } 699 1.1 brezak 700 1.2 brezak struct newrt { 701 1.3 mycroft u_int32_t mask; 702 1.3 mycroft u_int32_t origin; 703 1.2 brezak int metric; 704 1.2 brezak int pad; 705 1.2 brezak }; 706 1.2 brezak 707 1.5 mycroft static int 708 1.7 wiz compare_rts(const void *rt1, const void *rt2) 709 1.7 wiz { 710 1.13 lukem const struct newrt *r1 = (const struct newrt *)rt1; 711 1.13 lukem const struct newrt *r2 = (const struct newrt *)rt2; 712 1.7 wiz u_int32_t m1 = ntohl(r1->mask); 713 1.7 wiz u_int32_t m2 = ntohl(r2->mask); 714 1.7 wiz u_int32_t o1, o2; 715 1.2 brezak 716 1.2 brezak if (m1 > m2) 717 1.3 mycroft return (-1); 718 1.3 mycroft if (m1 < m2) 719 1.2 brezak return (1); 720 1.2 brezak 721 1.2 brezak /* masks are equal */ 722 1.2 brezak o1 = ntohl(r1->origin); 723 1.2 brezak o2 = ntohl(r2->origin); 724 1.2 brezak if (o1 > o2) 725 1.3 mycroft return (-1); 726 1.3 mycroft if (o1 < o2) 727 1.2 brezak return (1); 728 1.2 brezak return (0); 729 1.2 brezak } 730 1.1 brezak 731 1.1 brezak /* 732 1.1 brezak * Process an incoming route report message. 733 1.1 brezak */ 734 1.3 mycroft void 735 1.7 wiz accept_report(u_int32_t src, u_int32_t dst, char *p, int datalen, 736 1.7 wiz u_int32_t level) 737 1.1 brezak { 738 1.1 brezak vifi_t vifi; 739 1.7 wiz int width, i, nrt = 0; 740 1.1 brezak int metric; 741 1.3 mycroft u_int32_t mask; 742 1.3 mycroft u_int32_t origin; 743 1.2 brezak struct newrt rt[4096]; 744 1.1 brezak 745 1.1 brezak if ((vifi = find_vif(src, dst)) == NO_VIF) { 746 1.9 wiz logit(LOG_INFO, 0, 747 1.11 dsl "ignoring route report from non-neighbor %s", inet_fmt(src)); 748 1.1 brezak return; 749 1.1 brezak } 750 1.1 brezak 751 1.3 mycroft if (!update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level)) 752 1.1 brezak return; 753 1.1 brezak 754 1.2 brezak if (datalen > 2*4096) { 755 1.9 wiz logit(LOG_INFO, 0, 756 1.2 brezak "ignoring oversize (%d bytes) route report from %s", 757 1.11 dsl datalen, inet_fmt(src)); 758 1.2 brezak return; 759 1.2 brezak } 760 1.1 brezak 761 1.1 brezak while (datalen > 0) { /* Loop through per-mask lists. */ 762 1.3 mycroft 763 1.1 brezak if (datalen < 3) { 764 1.9 wiz logit(LOG_WARNING, 0, 765 1.3 mycroft "received truncated route report from %s", 766 1.11 dsl inet_fmt(src)); 767 1.1 brezak return; 768 1.1 brezak } 769 1.3 mycroft ((u_char *)&mask)[0] = 0xff; width = 1; 770 1.3 mycroft if ((((u_char *)&mask)[1] = *p++) != 0) width = 2; 771 1.3 mycroft if ((((u_char *)&mask)[2] = *p++) != 0) width = 3; 772 1.3 mycroft if ((((u_char *)&mask)[3] = *p++) != 0) width = 4; 773 1.5 mycroft if (!inet_valid_mask(ntohl(mask))) { 774 1.9 wiz logit(LOG_WARNING, 0, 775 1.5 mycroft "%s reports bogus netmask 0x%08x (%s)", 776 1.11 dsl inet_fmt(src), ntohl(mask), 777 1.11 dsl inet_fmt(mask)); 778 1.5 mycroft return; 779 1.5 mycroft } 780 1.1 brezak datalen -= 3; 781 1.1 brezak 782 1.1 brezak do { /* Loop through (origin, metric) pairs */ 783 1.1 brezak if (datalen < width + 1) { 784 1.9 wiz logit(LOG_WARNING, 0, 785 1.3 mycroft "received truncated route report from %s", 786 1.11 dsl inet_fmt(src)); 787 1.1 brezak return; 788 1.1 brezak } 789 1.1 brezak origin = 0; 790 1.1 brezak for (i = 0; i < width; ++i) 791 1.1 brezak ((char *)&origin)[i] = *p++; 792 1.1 brezak metric = *p++; 793 1.1 brezak datalen -= width + 1; 794 1.2 brezak rt[nrt].mask = mask; 795 1.2 brezak rt[nrt].origin = origin; 796 1.3 mycroft rt[nrt].metric = (metric & 0x7f); 797 1.2 brezak ++nrt; 798 1.1 brezak } while (!(metric & 0x80)); 799 1.1 brezak } 800 1.5 mycroft 801 1.2 brezak qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts); 802 1.2 brezak start_route_updates(); 803 1.3 mycroft /* 804 1.3 mycroft * If the last entry is default, change mask from 0xff000000 to 0 805 1.3 mycroft */ 806 1.3 mycroft if (rt[nrt-1].origin == 0) 807 1.3 mycroft rt[nrt-1].mask = 0; 808 1.3 mycroft 809 1.9 wiz logit(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt, 810 1.11 dsl inet_fmt(src), inet_fmt(dst)); 811 1.5 mycroft for (i = 0; i < nrt; ++i) { 812 1.5 mycroft if (i != 0 && rt[i].origin == rt[i-1].origin && 813 1.5 mycroft rt[i].mask == rt[i-1].mask) { 814 1.9 wiz logit(LOG_WARNING, 0, "%s reports duplicate route for %s", 815 1.11 dsl inet_fmt(src), 816 1.11 dsl inet_fmts(rt[i].origin, rt[i].mask)); 817 1.5 mycroft continue; 818 1.5 mycroft } 819 1.3 mycroft update_route(rt[i].origin, rt[i].mask, rt[i].metric, 820 1.3 mycroft src, vifi); 821 1.5 mycroft } 822 1.1 brezak 823 1.1 brezak if (routes_changed && !delay_change_reports) 824 1.1 brezak report_to_all_neighbors(CHANGED_ROUTES); 825 1.1 brezak } 826 1.1 brezak 827 1.1 brezak 828 1.1 brezak /* 829 1.1 brezak * Send a route report message to destination 'dst', via virtual interface 830 1.1 brezak * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. 831 1.1 brezak */ 832 1.3 mycroft void 833 1.7 wiz report(int which_routes, vifi_t vifi, u_int32_t dst) 834 1.1 brezak { 835 1.7 wiz struct rtentry *r; 836 1.7 wiz char *p; 837 1.7 wiz int i; 838 1.5 mycroft int datalen = 0; 839 1.5 mycroft int width = 0; 840 1.5 mycroft u_int32_t mask = 0; 841 1.3 mycroft u_int32_t src; 842 1.3 mycroft u_int32_t nflags; 843 1.1 brezak 844 1.1 brezak src = uvifs[vifi].uv_lcl_addr; 845 1.1 brezak 846 1.1 brezak p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; 847 1.1 brezak 848 1.3 mycroft #ifdef NOTYET 849 1.3 mycroft /* If I'm not a leaf, but the neighbor is a leaf, only advertise default */ 850 1.3 mycroft if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) { 851 1.3 mycroft *p++ = 0; /* 0xff000000 mask */ 852 1.3 mycroft *p++ = 0; 853 1.3 mycroft *p++ = 0; 854 1.3 mycroft *p++ = 0; /* class A net 0.0.0.0 == default */ 855 1.3 mycroft *p++ = 0x81; /*XXX metric 1, is this safe? */ 856 1.3 mycroft datalen += 5; 857 1.3 mycroft send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, 858 1.3 mycroft htonl(MROUTED_LEVEL), datalen); 859 1.3 mycroft return; 860 1.3 mycroft } 861 1.3 mycroft #endif 862 1.3 mycroft 863 1.3 mycroft nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS; 864 1.3 mycroft 865 1.3 mycroft for (r = rt_end; r != RT_ADDR; r = r->rt_prev) { 866 1.1 brezak 867 1.1 brezak if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) 868 1.1 brezak continue; 869 1.1 brezak 870 1.1 brezak /* 871 1.1 brezak * If there is no room for this route in the current message, 872 1.1 brezak * send the message and start a new one. 873 1.1 brezak */ 874 1.1 brezak if (datalen + ((r->rt_originmask == mask) ? 875 1.3 mycroft (width + 1) : 876 1.3 mycroft (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) { 877 1.1 brezak *(p-1) |= 0x80; 878 1.1 brezak send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, 879 1.3 mycroft htonl(MROUTED_LEVEL | nflags), datalen); 880 1.1 brezak 881 1.1 brezak p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; 882 1.1 brezak datalen = 0; 883 1.1 brezak mask = 0; 884 1.1 brezak } 885 1.1 brezak 886 1.5 mycroft if (r->rt_originmask != mask || datalen == 0) { 887 1.1 brezak mask = r->rt_originmask; 888 1.1 brezak width = r->rt_originwidth; 889 1.1 brezak if (datalen != 0) *(p-1) |= 0x80; 890 1.1 brezak *p++ = ((char *)&mask)[1]; 891 1.1 brezak *p++ = ((char *)&mask)[2]; 892 1.1 brezak *p++ = ((char *)&mask)[3]; 893 1.1 brezak datalen += 3; 894 1.1 brezak } 895 1.1 brezak 896 1.1 brezak for (i = 0; i < width; ++i) 897 1.1 brezak *p++ = ((char *)&(r->rt_origin))[i]; 898 1.1 brezak 899 1.1 brezak *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ? 900 1.3 mycroft (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */ 901 1.1 brezak (char)(r->rt_metric); 902 1.1 brezak 903 1.1 brezak datalen += width + 1; 904 1.1 brezak } 905 1.1 brezak 906 1.1 brezak if (datalen != 0) { 907 1.1 brezak *(p-1) |= 0x80; 908 1.1 brezak send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, 909 1.3 mycroft htonl(MROUTED_LEVEL | nflags), datalen); 910 1.1 brezak } 911 1.1 brezak } 912 1.1 brezak 913 1.1 brezak 914 1.1 brezak /* 915 1.1 brezak * Send a route report message to all neighboring routers. 916 1.1 brezak * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. 917 1.1 brezak */ 918 1.3 mycroft void 919 1.7 wiz report_to_all_neighbors(int which_routes) 920 1.1 brezak { 921 1.7 wiz vifi_t vifi; 922 1.7 wiz struct uvif *v; 923 1.7 wiz struct rtentry *r; 924 1.1 brezak int routes_changed_before; 925 1.1 brezak 926 1.1 brezak /* 927 1.1 brezak * Remember the state of the global routes_changed flag before 928 1.1 brezak * generating the reports, and clear the flag. 929 1.1 brezak */ 930 1.1 brezak routes_changed_before = routes_changed; 931 1.1 brezak routes_changed = FALSE; 932 1.1 brezak 933 1.1 brezak 934 1.1 brezak for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { 935 1.1 brezak if (v->uv_neighbors != NULL) { 936 1.1 brezak report(which_routes, vifi, 937 1.1 brezak (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr 938 1.3 mycroft : dvmrp_group); 939 1.1 brezak } 940 1.1 brezak } 941 1.1 brezak 942 1.1 brezak /* 943 1.1 brezak * If there were changed routes before we sent the reports AND 944 1.1 brezak * if no new changes occurred while sending the reports, clear 945 1.1 brezak * the change flags in the individual route entries. If changes 946 1.1 brezak * did occur while sending the reports, new reports will be 947 1.1 brezak * generated at the next timer interrupt. 948 1.1 brezak */ 949 1.1 brezak if (routes_changed_before && !routes_changed) { 950 1.1 brezak for (r = routing_table; r != NULL; r = r->rt_next) { 951 1.1 brezak r->rt_flags &= ~RTF_CHANGED; 952 1.1 brezak } 953 1.1 brezak } 954 1.1 brezak 955 1.1 brezak /* 956 1.1 brezak * Set a flag to inhibit further reports of changed routes until the 957 1.1 brezak * next timer interrupt. This is to alleviate update storms. 958 1.1 brezak */ 959 1.1 brezak delay_change_reports = TRUE; 960 1.2 brezak } 961 1.2 brezak 962 1.2 brezak /* 963 1.2 brezak * Send a route report message to destination 'dst', via virtual interface 964 1.2 brezak * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES. 965 1.2 brezak */ 966 1.5 mycroft static int 967 1.7 wiz report_chunk(struct rtentry *start_rt, vifi_t vifi, u_int32_t dst) 968 1.2 brezak { 969 1.7 wiz struct rtentry *r; 970 1.7 wiz char *p; 971 1.7 wiz int i; 972 1.7 wiz int nrt = 0; 973 1.5 mycroft int datalen = 0; 974 1.5 mycroft int width = 0; 975 1.5 mycroft u_int32_t mask = 0; 976 1.3 mycroft u_int32_t src; 977 1.3 mycroft u_int32_t nflags; 978 1.2 brezak 979 1.2 brezak src = uvifs[vifi].uv_lcl_addr; 980 1.2 brezak p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN; 981 1.2 brezak 982 1.3 mycroft nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS; 983 1.3 mycroft 984 1.3 mycroft for (r = start_rt; r != RT_ADDR; r = r->rt_prev) { 985 1.3 mycroft 986 1.3 mycroft #ifdef NOTYET 987 1.3 mycroft /* Don't send poisoned routes back to parents if I am a leaf */ 988 1.3 mycroft if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi) 989 1.3 mycroft && (r->rt_metric > 1)) { 990 1.3 mycroft ++nrt; 991 1.3 mycroft continue; 992 1.3 mycroft } 993 1.3 mycroft #endif 994 1.3 mycroft 995 1.2 brezak /* 996 1.2 brezak * If there is no room for this route in the current message, 997 1.2 brezak * send it & return how many routes we sent. 998 1.2 brezak */ 999 1.2 brezak if (datalen + ((r->rt_originmask == mask) ? 1000 1.3 mycroft (width + 1) : 1001 1.3 mycroft (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) { 1002 1.2 brezak *(p-1) |= 0x80; 1003 1.2 brezak send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, 1004 1.3 mycroft htonl(MROUTED_LEVEL | nflags), datalen); 1005 1.2 brezak return (nrt); 1006 1.2 brezak } 1007 1.5 mycroft if (r->rt_originmask != mask || datalen == 0) { 1008 1.2 brezak mask = r->rt_originmask; 1009 1.2 brezak width = r->rt_originwidth; 1010 1.2 brezak if (datalen != 0) *(p-1) |= 0x80; 1011 1.2 brezak *p++ = ((char *)&mask)[1]; 1012 1.2 brezak *p++ = ((char *)&mask)[2]; 1013 1.2 brezak *p++ = ((char *)&mask)[3]; 1014 1.2 brezak datalen += 3; 1015 1.2 brezak } 1016 1.2 brezak for (i = 0; i < width; ++i) 1017 1.2 brezak *p++ = ((char *)&(r->rt_origin))[i]; 1018 1.2 brezak 1019 1.2 brezak *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ? 1020 1.3 mycroft (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */ 1021 1.2 brezak (char)(r->rt_metric); 1022 1.2 brezak ++nrt; 1023 1.2 brezak datalen += width + 1; 1024 1.2 brezak } 1025 1.2 brezak if (datalen != 0) { 1026 1.2 brezak *(p-1) |= 0x80; 1027 1.2 brezak send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT, 1028 1.3 mycroft htonl(MROUTED_LEVEL | nflags), datalen); 1029 1.2 brezak } 1030 1.2 brezak return (nrt); 1031 1.2 brezak } 1032 1.2 brezak 1033 1.2 brezak /* 1034 1.2 brezak * send the next chunk of our routing table to all neighbors. 1035 1.3 mycroft * return the length of the smallest chunk we sent out. 1036 1.2 brezak */ 1037 1.3 mycroft int 1038 1.7 wiz report_next_chunk(void) 1039 1.2 brezak { 1040 1.7 wiz vifi_t vifi; 1041 1.7 wiz struct uvif *v; 1042 1.7 wiz struct rtentry *sr; 1043 1.7 wiz int i, n = 0, min = 20000; 1044 1.2 brezak static int start_rt; 1045 1.2 brezak 1046 1.2 brezak if (nroutes <= 0) 1047 1.2 brezak return (0); 1048 1.2 brezak 1049 1.2 brezak /* 1050 1.2 brezak * find this round's starting route. 1051 1.2 brezak */ 1052 1.3 mycroft for (sr = rt_end, i = start_rt; --i >= 0; ) { 1053 1.3 mycroft sr = sr->rt_prev; 1054 1.3 mycroft if (sr == RT_ADDR) 1055 1.3 mycroft sr = rt_end; 1056 1.2 brezak } 1057 1.3 mycroft 1058 1.2 brezak /* 1059 1.2 brezak * send one chunk of routes starting at this round's start to 1060 1.2 brezak * all our neighbors. 1061 1.2 brezak */ 1062 1.2 brezak for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) { 1063 1.3 mycroft if ((v->uv_neighbors != NULL) 1064 1.3 mycroft #ifdef NOTYET 1065 1.3 mycroft && !(v->uv_flags & VIFF_LEAF) 1066 1.3 mycroft #endif 1067 1.3 mycroft ) { 1068 1.2 brezak n = report_chunk(sr, vifi, 1069 1.3 mycroft (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr 1070 1.3 mycroft : dvmrp_group); 1071 1.3 mycroft if (n < min) 1072 1.3 mycroft min = n; 1073 1.2 brezak } 1074 1.2 brezak } 1075 1.3 mycroft if (min == 20000) 1076 1.3 mycroft min = 0; /* Neighborless router didn't send any routes */ 1077 1.3 mycroft 1078 1.3 mycroft n = min; 1079 1.9 wiz logit(LOG_INFO, 0, "update %d starting at %d of %d", 1080 1.3 mycroft n, (nroutes - start_rt), nroutes); 1081 1.3 mycroft 1082 1.2 brezak start_rt = (start_rt + n) % nroutes; 1083 1.2 brezak return (n); 1084 1.1 brezak } 1085 1.1 brezak 1086 1.1 brezak 1087 1.1 brezak /* 1088 1.1 brezak * Print the contents of the routing table on file 'fp'. 1089 1.1 brezak */ 1090 1.3 mycroft void 1091 1.7 wiz dump_routes(FILE *fp) 1092 1.1 brezak { 1093 1.7 wiz struct rtentry *r; 1094 1.7 wiz vifi_t i; 1095 1.3 mycroft 1096 1.1 brezak 1097 1.1 brezak fprintf(fp, 1098 1.3 mycroft "Multicast Routing Table (%u %s)\n%s\n", 1099 1.3 mycroft nroutes, (nroutes == 1) ? "entry" : "entries", 1100 1.3 mycroft " Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs"); 1101 1.1 brezak 1102 1.1 brezak for (r = routing_table; r != NULL; r = r->rt_next) { 1103 1.1 brezak 1104 1.3 mycroft fprintf(fp, " %-18s %-15s ", 1105 1.11 dsl inet_fmts(r->rt_origin, r->rt_originmask), 1106 1.11 dsl (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway)); 1107 1.1 brezak 1108 1.1 brezak fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ", 1109 1.1 brezak r->rt_metric); 1110 1.1 brezak 1111 1.3 mycroft fprintf(fp, " %3u %3u ", r->rt_timer, r->rt_parent); 1112 1.1 brezak 1113 1.1 brezak for (i = 0; i < numvifs; ++i) { 1114 1.1 brezak if (VIFM_ISSET(i, r->rt_children)) { 1115 1.1 brezak fprintf(fp, " %u%c", 1116 1.1 brezak i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' '); 1117 1.1 brezak } 1118 1.1 brezak } 1119 1.1 brezak fprintf(fp, "\n"); 1120 1.1 brezak } 1121 1.1 brezak fprintf(fp, "\n"); 1122 1.3 mycroft } 1123 1.3 mycroft 1124 1.3 mycroft struct rtentry * 1125 1.7 wiz determine_route(u_int32_t src) 1126 1.3 mycroft { 1127 1.3 mycroft struct rtentry *rt; 1128 1.3 mycroft 1129 1.3 mycroft for (rt = routing_table; rt != NULL; rt = rt->rt_next) { 1130 1.3 mycroft if (rt->rt_origin == (src & rt->rt_originmask)) 1131 1.3 mycroft break; 1132 1.3 mycroft } 1133 1.3 mycroft return rt; 1134 1.1 brezak } 1135