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