]> git.ipfire.org Git - thirdparty/bird.git/blame - nest/rt-table.c
Backport some minor changes from int-new
[thirdparty/bird.git] / nest / rt-table.c
CommitLineData
62aa008a 1/*
58740ed4 2 * BIRD -- Routing Tables
62aa008a 3 *
50fe90ed 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
62aa008a
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
58740ed4
MM
9/**
10 * DOC: Routing tables
11 *
12 * Routing tables are probably the most important structures BIRD uses. They
13 * hold all the information about known networks, the associated routes and
14 * their attributes.
15 *
725270cb 16 * There are multiple routing tables (a primary one together with any
58740ed4
MM
17 * number of secondary ones if requested by the configuration). Each table
18 * is basically a FIB containing entries describing the individual
58f7d004 19 * destination networks. For each network (represented by structure &net),
725270cb
MM
20 * there is a one-way linked list of route entries (&rte), the first entry
21 * on the list being the best one (i.e., the one we currently use
58740ed4
MM
22 * for routing), the order of the other ones is undetermined.
23 *
24 * The &rte contains information specific to the route (preference, protocol
25 * metrics, time of last modification etc.) and a pointer to a &rta structure
26 * (see the route attribute module for a precise explanation) holding the
27 * remaining route attributes which are expected to be shared by multiple
28 * routes in order to conserve memory.
29 */
30
6b9fa320 31#undef LOCAL_DEBUG
1a54b1c6 32
62aa008a
MM
33#include "nest/bird.h"
34#include "nest/route.h"
2326b001 35#include "nest/protocol.h"
730f2e2c
MM
36#include "nest/cli.h"
37#include "nest/iface.h"
2326b001 38#include "lib/resource.h"
5996da6a 39#include "lib/event.h"
730f2e2c 40#include "lib/string.h"
0e02abfd 41#include "conf/conf.h"
529c4149 42#include "filter/filter.h"
221135d6 43#include "lib/string.h"
10af3676 44#include "lib/alloca.h"
7d875e09 45
acb60628
OZ
46pool *rt_table_pool;
47
2326b001 48static slab *rte_slab;
e2dc2f30 49static linpool *rte_update_pool;
2326b001 50
0e02abfd 51static list routing_tables;
5996da6a 52
6887f409 53static byte *rt_format_via(rte *e);
cfe34a31
OZ
54static void rt_free_hostcache(rtable *tab);
55static void rt_notify_hostcache(rtable *tab, net *net);
56static void rt_update_hostcache(rtable *tab);
57static void rt_next_hop_update(rtable *tab);
0c791f87 58static inline int rt_prune_table(rtable *tab);
cfe34a31 59static inline void rt_schedule_gc(rtable *tab);
0c791f87
OZ
60static inline void rt_schedule_prune(rtable *tab);
61
cfd46ee4 62
d1e146f2
OZ
63/* Like fib_route(), but skips empty net entries */
64static net *
65net_route(rtable *tab, ip_addr a, int len)
66{
67 ip_addr a0;
68 net *n;
69
70 while (len >= 0)
71 {
72 a0 = ipa_and(a, ipa_mkmask(len));
73 n = fib_find(&tab->fib, &a0, len);
cf98be7b 74 if (n && rte_is_valid(n->routes))
d1e146f2
OZ
75 return n;
76 len--;
77 }
78 return NULL;
79}
80
5996da6a 81static void
2326b001
MM
82rte_init(struct fib_node *N)
83{
84 net *n = (net *) N;
85
4c45595e 86 N->flags = 0;
2326b001
MM
87 n->routes = NULL;
88}
89
58740ed4
MM
90/**
91 * rte_find - find a route
92 * @net: network node
094d2bdb 93 * @src: route source
58740ed4
MM
94 *
95 * The rte_find() function returns a route for destination @net
094d2bdb 96 * which is from route source @src.
58740ed4 97 */
2326b001 98rte *
094d2bdb 99rte_find(net *net, struct rte_src *src)
2326b001
MM
100{
101 rte *e = net->routes;
102
094d2bdb 103 while (e && e->attrs->src != src)
2326b001
MM
104 e = e->next;
105 return e;
106}
107
58740ed4
MM
108/**
109 * rte_get_temp - get a temporary &rte
3ce8c610 110 * @a: attributes to assign to the new route (a &rta; in case it's
2e9b2421 111 * un-cached, rte_update() will create a cached copy automatically)
58740ed4
MM
112 *
113 * Create a temporary &rte and bind it with the attributes @a.
114 * Also set route preference to the default preference set for
115 * the protocol.
116 */
2326b001
MM
117rte *
118rte_get_temp(rta *a)
119{
120 rte *e = sl_alloc(rte_slab);
121
122 e->attrs = a;
0cdbd397 123 e->flags = 0;
094d2bdb 124 e->pref = a->src->proto->preference;
2326b001
MM
125 return e;
126}
127
e2dc2f30
MM
128rte *
129rte_do_cow(rte *r)
130{
131 rte *e = sl_alloc(rte_slab);
132
133 memcpy(e, r, sizeof(rte));
134 e->attrs = rta_clone(r->attrs);
135 e->flags = 0;
136 return e;
137}
138
8d9eef17
OZ
139/**
140 * rte_cow_rta - get a private writable copy of &rte with writable &rta
141 * @r: a route entry to be copied
142 * @lp: a linpool from which to allocate &rta
143 *
144 * rte_cow_rta() takes a &rte and prepares it and associated &rta for
145 * modification. There are three possibilities: First, both &rte and &rta are
146 * private copies, in that case they are returned unchanged. Second, &rte is
147 * private copy, but &rta is cached, in that case &rta is duplicated using
148 * rta_do_cow(). Third, both &rte is shared and &rta is cached, in that case
149 * both structures are duplicated by rte_do_cow() and rta_do_cow().
150 *
151 * Note that in the second case, cached &rta loses one reference, while private
152 * copy created by rta_do_cow() is a shallow copy sharing indirect data (eattrs,
153 * nexthops, ...) with it. To work properly, original shared &rta should have
154 * another reference during the life of created private copy.
155 *
156 * Result: a pointer to the new writable &rte with writable &rta.
157 */
158rte *
159rte_cow_rta(rte *r, linpool *lp)
160{
161 if (!rta_is_cached(r->attrs))
162 return r;
163
164 rte *e = rte_cow(r);
165 rta *a = rta_do_cow(r->attrs, lp);
166 rta_free(e->attrs);
167 e->attrs = a;
168 return e;
169}
170
2326b001
MM
171static int /* Actually better or at least as good as */
172rte_better(rte *new, rte *old)
173{
d9f330c5
MM
174 int (*better)(rte *, rte *);
175
cf98be7b 176 if (!rte_is_valid(old))
2326b001 177 return 1;
cf98be7b
OZ
178 if (!rte_is_valid(new))
179 return 0;
180
2326b001
MM
181 if (new->pref > old->pref)
182 return 1;
183 if (new->pref < old->pref)
184 return 0;
094d2bdb 185 if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
4c1b4e1a
MM
186 {
187 /*
188 * If the user has configured protocol preferences, so that two different protocols
189 * have the same preference, try to break the tie by comparing addresses. Not too
190 * useful, but keeps the ordering of routes unambiguous.
191 */
094d2bdb 192 return new->attrs->src->proto->proto > old->attrs->src->proto->proto;
4c1b4e1a 193 }
094d2bdb 194 if (better = new->attrs->src->proto->rte_better)
d9f330c5
MM
195 return better(new, old);
196 return 0;
2326b001
MM
197}
198
8d9eef17
OZ
199static int
200rte_mergable(rte *pri, rte *sec)
201{
202 int (*mergable)(rte *, rte *);
203
204 if (!rte_is_valid(pri) || !rte_is_valid(sec))
205 return 0;
206
207 if (pri->pref != sec->pref)
208 return 0;
209
210 if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto)
211 return 0;
212
213 if (mergable = pri->attrs->src->proto->rte_mergable)
214 return mergable(pri, sec);
215
216 return 0;
217}
218
cfd46ee4
MM
219static void
220rte_trace(struct proto *p, rte *e, int dir, char *msg)
221{
6887f409 222 log(L_TRACE "%s %c %s %I/%d %s", p->name, dir, msg, e->net->n.prefix, e->net->n.pxlen, rt_format_via(e));
cfd46ee4
MM
223}
224
225static inline void
ae80a2de 226rte_trace_in(uint flag, struct proto *p, rte *e, char *msg)
cfd46ee4
MM
227{
228 if (p->debug & flag)
b0a47440 229 rte_trace(p, e, '>', msg);
cfd46ee4
MM
230}
231
232static inline void
ae80a2de 233rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
cfd46ee4
MM
234{
235 if (p->debug & flag)
b0a47440 236 rte_trace(p, e, '<', msg);
cfd46ee4
MM
237}
238
00a09f3c 239static rte *
a290da25 240export_filter_(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
529c4149 241{
c0adf7e9
OZ
242 struct proto *p = ah->proto;
243 struct filter *filter = ah->out_filter;
244 struct proto_stats *stats = ah->stats;
00a09f3c
OZ
245 ea_list *tmpb = NULL;
246 rte *rt;
247 int v;
c0adf7e9 248
00a09f3c
OZ
249 rt = rt0;
250 *rt_free = NULL;
7de45ba4 251
00a09f3c 252 if (!tmpa)
db027a41
OZ
253 tmpa = &tmpb;
254
f2dd602f 255 *tmpa = rte_make_tmp_attrs(rt, pool);
925fe2d3 256
a290da25 257 v = p->import_control ? p->import_control(p, &rt, tmpa, pool) : 0;
00a09f3c
OZ
258 if (v < 0)
259 {
260 if (silent)
261 goto reject;
11361a10 262
00a09f3c 263 stats->exp_updates_rejected++;
36da2857
OZ
264 if (v == RIC_REJECT)
265 rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
00a09f3c
OZ
266 goto reject;
267 }
268 if (v > 0)
e2dc2f30 269 {
00a09f3c
OZ
270 if (!silent)
271 rte_trace_out(D_FILTERS, p, rt, "forced accept by protocol");
272 goto accept;
e2dc2f30 273 }
925fe2d3 274
00a09f3c 275 v = filter && ((filter == FILTER_REJECT) ||
a290da25 276 (f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT));
00a09f3c
OZ
277 if (v)
278 {
279 if (silent)
280 goto reject;
281
282 stats->exp_updates_filtered++;
283 rte_trace_out(D_FILTERS, p, rt, "filtered out");
284 goto reject;
e2dc2f30 285 }
925fe2d3 286
00a09f3c
OZ
287 accept:
288 if (rt != rt0)
289 *rt_free = rt;
290 return rt;
291
292 reject:
293 /* Discard temporary rte */
294 if (rt != rt0)
295 rte_free(rt);
296 return NULL;
297}
298
a290da25
PT
299static inline rte *
300export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
301{
302 return export_filter_(ah, rt0, rt_free, tmpa, rte_update_pool, silent);
303}
304
00a09f3c
OZ
305static void
306do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
307{
308 struct proto *p = ah->proto;
309 struct proto_stats *stats = ah->stats;
925fe2d3 310
abced4a9 311
ab758e4f 312 /*
abced4a9
OZ
313 * First, apply export limit.
314 *
ab758e4f
OZ
315 * Export route limits has several problems. Because exp_routes
316 * counter is reset before refeed, we don't really know whether
abced4a9 317 * limit is breached and whether the update is new or not. Therefore
ab758e4f
OZ
318 * the number of really exported routes may exceed the limit
319 * temporarily (routes exported before and new routes in refeed).
320 *
321 * Minor advantage is that if the limit is decreased and refeed is
322 * requested, the number of exported routes really decrease.
323 *
324 * Second problem is that with export limits, we don't know whether
325 * old was really exported (it might be blocked by limit). When a
326 * withdraw is exported, we announce it even when the previous
327 * update was blocked. This is not a big issue, but the same problem
328 * is in updating exp_routes counter. Therefore, to be consistent in
329 * increases and decreases of exp_routes, we count exported routes
330 * regardless of blocking by limits.
331 *
332 * Similar problem is in handling updates - when a new route is
333 * received and blocking is active, the route would be blocked, but
334 * when an update for the route will be received later, the update
335 * would be propagated (as old != NULL). Therefore, we have to block
336 * also non-new updates (contrary to import blocking).
337 */
925fe2d3 338
d9b77cc2 339 struct proto_limit *l = ah->out_limit;
ab758e4f 340 if (l && new)
d9b77cc2 341 {
ab758e4f 342 if ((!old || refeed) && (stats->exp_routes >= l->limit))
b662290f 343 proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
d9b77cc2
OZ
344
345 if (l->state == PLS_BLOCKED)
346 {
ab758e4f 347 stats->exp_routes++; /* see note above */
d9b77cc2
OZ
348 stats->exp_updates_rejected++;
349 rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
ab758e4f 350 new = NULL;
abced4a9
OZ
351
352 if (!old)
353 return;
d9b77cc2
OZ
354 }
355 }
356
ab758e4f 357
925fe2d3 358 if (new)
9db74169 359 stats->exp_updates_accepted++;
925fe2d3 360 else
9db74169 361 stats->exp_withdraws_accepted++;
925fe2d3 362
8a7fb885
OZ
363 /* Hack: We do not decrease exp_routes during refeed, we instead
364 reset exp_routes at the start of refeed. */
925fe2d3 365 if (new)
9db74169 366 stats->exp_routes++;
8a7fb885 367 if (old && !refeed)
9db74169 368 stats->exp_routes--;
925fe2d3 369
cfd46ee4
MM
370 if (p->debug & D_ROUTES)
371 {
372 if (new && old)
373 rte_trace_out(D_ROUTES, p, new, "replaced");
374 else if (new)
375 rte_trace_out(D_ROUTES, p, new, "added");
349e21bb 376 else if (old)
cfd46ee4
MM
377 rte_trace_out(D_ROUTES, p, old, "removed");
378 }
08f0290a 379 if (!new)
c0adf7e9 380 p->rt_notify(p, ah->table, net, NULL, old, NULL);
08f0290a
MM
381 else if (tmpa)
382 {
2f711231
MM
383 ea_list *t = tmpa;
384 while (t->next)
385 t = t->next;
386 t->next = new->attrs->eattrs;
c0adf7e9 387 p->rt_notify(p, ah->table, net, new, old, tmpa);
2f711231 388 t->next = NULL;
08f0290a
MM
389 }
390 else
c0adf7e9 391 p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
00a09f3c
OZ
392}
393
00a09f3c 394static void
db027a41 395rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int refeed)
00a09f3c 396{
86f567e1 397 struct proto *p = ah->proto;
00a09f3c
OZ
398 struct proto_stats *stats = ah->stats;
399
86f567e1
OZ
400 rte *new = new0;
401 rte *old = old0;
00a09f3c
OZ
402 rte *new_free = NULL;
403 rte *old_free = NULL;
db027a41 404 ea_list *tmpa = NULL;
00a09f3c
OZ
405
406 if (new)
407 stats->exp_updates_received++;
408 else
409 stats->exp_withdraws_received++;
410
411 /*
412 * This is a tricky part - we don't know whether route 'old' was
413 * exported to protocol 'p' or was filtered by the export filter.
414 * We try to run the export filter to know this to have a correct
415 * value in 'old' argument of rte_update (and proper filter value)
416 *
417 * FIXME - this is broken because 'configure soft' may change
418 * filters but keep routes. Refeed is expected to be called after
419 * change of the filters and with old == new, therefore we do not
86f567e1 420 * even try to run the filter on an old route, This may lead to
00a09f3c
OZ
421 * 'spurious withdraws' but ensure that there are no 'missing
422 * withdraws'.
423 *
424 * This is not completely safe as there is a window between
425 * reconfiguration and the end of refeed - if a newly filtered
426 * route disappears during this period, proper withdraw is not
427 * sent (because old would be also filtered) and the route is
428 * not refeeded (because it disappeared before that).
429 */
430
431 if (new)
432 new = export_filter(ah, new, &new_free, &tmpa, 0);
433
434 if (old && !refeed)
435 old = export_filter(ah, old, &old_free, NULL, 1);
436
00a09f3c 437 if (!new && !old)
86f567e1
OZ
438 {
439 /*
440 * As mentioned above, 'old' value may be incorrect in some race conditions.
441 * We generally ignore it with the exception of withdraw to pipe protocol.
442 * In that case we rather propagate unfiltered withdraws regardless of
443 * export filters to ensure that when a protocol is flushed, its routes are
444 * removed from all tables. Possible spurious unfiltered withdraws are not
445 * problem here as they are ignored if there is no corresponding route at
446 * the other end of the pipe. We directly call rt_notify() hook instead of
447 * do_rt_notify() to avoid logging and stat counters.
448 */
449
450#ifdef CONFIG_PIPE
451 if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto))
452 p->rt_notify(p, ah->table, net, NULL, old0, NULL);
453#endif
454
00a09f3c 455 return;
86f567e1 456 }
00a09f3c
OZ
457
458 do_rt_notify(ah, net, new, old, tmpa, refeed);
459
460 /* Discard temporary rte's */
461 if (new_free)
462 rte_free(new_free);
463 if (old_free)
464 rte_free(old_free);
465}
466
467static void
db027a41 468rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
00a09f3c
OZ
469{
470 // struct proto *p = ah->proto;
471 struct proto_stats *stats = ah->stats;
472
db027a41 473 rte *r;
00a09f3c
OZ
474 rte *new_best = NULL;
475 rte *old_best = NULL;
476 rte *new_free = NULL;
477 rte *old_free = NULL;
db027a41 478 ea_list *tmpa = NULL;
00a09f3c 479
cf98be7b
OZ
480 /* Used to track whether we met old_changed position. If before_old is NULL
481 old_changed was the first and we met it implicitly before current best route. */
482 int old_meet = old_changed && !before_old;
483
484 /* Note that before_old is either NULL or valid (not rejected) route.
485 If old_changed is valid, before_old have to be too. If old changed route
486 was not valid, caller must use NULL for both old_changed and before_old. */
00a09f3c
OZ
487
488 if (new_changed)
489 stats->exp_updates_received++;
490 else
491 stats->exp_withdraws_received++;
492
493 /* First, find the new_best route - first accepted by filters */
cf98be7b 494 for (r=net->routes; rte_is_valid(r); r=r->next)
00a09f3c
OZ
495 {
496 if (new_best = export_filter(ah, r, &new_free, &tmpa, 0))
497 break;
498
499 /* Note if we walked around the position of old_changed route */
500 if (r == before_old)
501 old_meet = 1;
502 }
503
504 /*
505 * Second, handle the feed case. That means we do not care for
506 * old_best. It is NULL for feed, and the new_best for refeed.
507 * For refeed, there is a hack similar to one in rt_notify_basic()
508 * to ensure withdraws in case of changed filters
509 */
510 if (feed)
511 {
512 if (feed == 2) /* refeed */
cf98be7b
OZ
513 old_best = new_best ? new_best :
514 (rte_is_valid(net->routes) ? net->routes : NULL);
00a09f3c
OZ
515 else
516 old_best = NULL;
517
518 if (!new_best && !old_best)
519 return;
520
521 goto found;
522 }
523
524 /*
525 * Now, we find the old_best route. Generally, it is the same as the
526 * new_best, unless new_best is the same as new_changed or
527 * old_changed is accepted before new_best.
528 *
529 * There are four cases:
530 *
531 * - We would find and accept old_changed before new_best, therefore
532 * old_changed is old_best. In remaining cases we suppose this
533 * is not true.
534 *
535 * - We found no new_best, therefore there is also no old_best and
536 * we ignore this withdraw.
537 *
538 * - We found new_best different than new_changed, therefore
539 * old_best is the same as new_best and we ignore this update.
540 *
541 * - We found new_best the same as new_changed, therefore it cannot
542 * be old_best and we have to continue search for old_best.
543 */
544
545 /* First case */
546 if (old_meet)
547 if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
548 goto found;
549
550 /* Second case */
551 if (!new_best)
552 return;
d9b77cc2 553
26822d8f 554 /* Third case, we use r instead of new_best, because export_filter() could change it */
00a09f3c
OZ
555 if (r != new_changed)
556 {
557 if (new_free)
558 rte_free(new_free);
559 return;
560 }
561
562 /* Fourth case */
cf98be7b 563 for (r=r->next; rte_is_valid(r); r=r->next)
00a09f3c
OZ
564 {
565 if (old_best = export_filter(ah, r, &old_free, NULL, 1))
566 goto found;
567
568 if (r == before_old)
569 if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
570 goto found;
571 }
572
573 /* Implicitly, old_best is NULL and new_best is non-NULL */
574
575 found:
576 do_rt_notify(ah, net, new_best, old_best, tmpa, (feed == 2));
577
578 /* Discard temporary rte's */
579 if (new_free)
580 rte_free(new_free);
581 if (old_free)
582 rte_free(old_free);
529c4149
MM
583}
584
8d9eef17
OZ
585
586static struct mpnh *
a290da25 587mpnh_merge_rta(struct mpnh *nhs, rta *a, linpool *pool, int max)
8d9eef17
OZ
588{
589 struct mpnh nh = { .gw = a->gw, .iface = a->iface };
590 struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh;
2e7fb11a 591 return mpnh_merge(nhs, nh2, 1, 0, max, pool);
8d9eef17
OZ
592}
593
594rte *
a290da25 595rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
8d9eef17
OZ
596{
597 // struct proto *p = ah->proto;
598 struct mpnh *nhs = NULL;
599 rte *best0, *best, *rt0, *rt, *tmp;
600
601 best0 = net->routes;
602 *rt_free = NULL;
603
604 if (!rte_is_valid(best0))
605 return NULL;
606
a290da25 607 best = export_filter_(ah, best0, rt_free, tmpa, pool, silent);
8d9eef17
OZ
608
609 if (!best || !rte_is_reachable(best))
610 return best;
611
612 for (rt0 = best0->next; rt0; rt0 = rt0->next)
613 {
614 if (!rte_mergable(best0, rt0))
615 continue;
616
a290da25 617 rt = export_filter_(ah, rt0, &tmp, NULL, pool, 1);
8d9eef17
OZ
618
619 if (!rt)
620 continue;
621
622 if (rte_is_reachable(rt))
a290da25 623 nhs = mpnh_merge_rta(nhs, rt->attrs, pool, ah->proto->merge_limit);
8d9eef17
OZ
624
625 if (tmp)
626 rte_free(tmp);
627 }
628
629 if (nhs)
630 {
a290da25 631 nhs = mpnh_merge_rta(nhs, best->attrs, pool, ah->proto->merge_limit);
8d9eef17
OZ
632
633 if (nhs->next)
634 {
a290da25 635 best = rte_cow_rta(best, pool);
8d9eef17
OZ
636 best->attrs->dest = RTD_MULTIPATH;
637 best->attrs->nexthops = nhs;
638 }
639 }
640
641 if (best != best0)
642 *rt_free = best;
643
644 return best;
645}
646
647
648static void
649rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed,
650 rte *new_best, rte*old_best, int refeed)
651{
652 // struct proto *p = ah->proto;
653
654 rte *new_best_free = NULL;
655 rte *old_best_free = NULL;
656 rte *new_changed_free = NULL;
657 rte *old_changed_free = NULL;
658 ea_list *tmpa = NULL;
659
660 /* We assume that all rte arguments are either NULL or rte_is_valid() */
661
662 /* This check should be done by the caller */
663 if (!new_best && !old_best)
664 return;
665
666 /* Check whether the change is relevant to the merged route */
667 if ((new_best == old_best) && !refeed)
668 {
669 new_changed = rte_mergable(new_best, new_changed) ?
670 export_filter(ah, new_changed, &new_changed_free, NULL, 1) : NULL;
671
672 old_changed = rte_mergable(old_best, old_changed) ?
673 export_filter(ah, old_changed, &old_changed_free, NULL, 1) : NULL;
674
675 if (!new_changed && !old_changed)
676 return;
677 }
678
679 if (new_best)
680 ah->stats->exp_updates_received++;
681 else
682 ah->stats->exp_withdraws_received++;
683
684 /* Prepare new merged route */
685 if (new_best)
a290da25 686 new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, rte_update_pool, 0);
8d9eef17
OZ
687
688 /* Prepare old merged route (without proper merged next hops) */
689 /* There are some issues with running filter on old route - see rt_notify_basic() */
690 if (old_best && !refeed)
691 old_best = export_filter(ah, old_best, &old_best_free, NULL, 1);
692
693 if (new_best || old_best)
694 do_rt_notify(ah, net, new_best, old_best, tmpa, refeed);
695
696 /* Discard temporary rte's */
697 if (new_best_free)
698 rte_free(new_best_free);
699 if (old_best_free)
700 rte_free(old_best_free);
701 if (new_changed_free)
702 rte_free(new_changed_free);
703 if (old_changed_free)
704 rte_free(old_changed_free);
705}
706
707
9a8f20fc
MM
708/**
709 * rte_announce - announce a routing table change
710 * @tab: table the route has been added to
23ac9e9a 711 * @type: type of route announcement (RA_OPTIMAL or RA_ANY)
9a8f20fc
MM
712 * @net: network in question
713 * @new: the new route to be announced
23ac9e9a 714 * @old: the previous route for the same network
8e433d6a
PT
715 * @new_best: the new best route for the same network
716 * @old_best: the previous best route for the same network
717 * @before_old: The previous route before @old for the same network.
718 * If @before_old is NULL @old was the first.
9a8f20fc
MM
719 *
720 * This function gets a routing table update and announces it
f98e2915
OZ
721 * to all protocols that acccepts given type of route announcement
722 * and are connected to the same table by their announcement hooks.
9a8f20fc 723 *
8e433d6a 724 * Route announcement of type %RA_OPTIMAL si generated when optimal
f98e2915
OZ
725 * route (in routing table @tab) changes. In that case @old stores the
726 * old optimal route.
23ac9e9a 727 *
8e433d6a 728 * Route announcement of type %RA_ANY si generated when any route (in
f98e2915
OZ
729 * routing table @tab) changes In that case @old stores the old route
730 * from the same protocol.
731 *
732 * For each appropriate protocol, we first call its import_control()
733 * hook which performs basic checks on the route (each protocol has a
734 * right to veto or force accept of the route before any filter is
735 * asked) and adds default values of attributes specific to the new
736 * protocol (metrics, tags etc.). Then it consults the protocol's
737 * export filter and if it accepts the route, the rt_notify() hook of
738 * the protocol gets called.
9a8f20fc 739 */
e2dc2f30 740static void
8d9eef17
OZ
741rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
742 rte *new_best, rte *old_best, rte *before_old)
2326b001 743{
8d9eef17
OZ
744 if (!rte_is_valid(new))
745 new = NULL;
746
cf98be7b
OZ
747 if (!rte_is_valid(old))
748 old = before_old = NULL;
749
8d9eef17
OZ
750 if (!rte_is_valid(new_best))
751 new_best = NULL;
752
753 if (!rte_is_valid(old_best))
754 old_best = NULL;
cf98be7b
OZ
755
756 if (!old && !new)
757 return;
2326b001 758
925fe2d3
OZ
759 if (type == RA_OPTIMAL)
760 {
761 if (new)
094d2bdb 762 new->attrs->src->proto->stats.pref_routes++;
925fe2d3 763 if (old)
094d2bdb 764 old->attrs->src->proto->stats.pref_routes--;
cfe34a31
OZ
765
766 if (tab->hostcache)
767 rt_notify_hostcache(tab, net);
925fe2d3
OZ
768 }
769
cf98be7b 770 struct announce_hook *a;
0e02abfd 771 WALK_LIST(a, tab->hooks)
0a2e9d9f 772 {
0c791f87 773 ASSERT(a->proto->export_state != ES_DOWN);
23ac9e9a 774 if (a->proto->accept_ra_types == type)
00a09f3c 775 if (type == RA_ACCEPTED)
db027a41 776 rt_notify_accepted(a, net, new, old, before_old, 0);
8d9eef17
OZ
777 else if (type == RA_MERGED)
778 rt_notify_merged(a, net, new, old, new_best, old_best, 0);
00a09f3c 779 else
db027a41 780 rt_notify_basic(a, net, new, old, 0);
0a2e9d9f 781 }
2326b001
MM
782}
783
421838ff
MM
784static inline int
785rte_validate(rte *e)
786{
787 int c;
788 net *n = e->net;
789
852b7062 790 if ((n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
cfd46ee4 791 {
ab164971 792 log(L_WARN "Ignoring bogus prefix %I/%d received via %s",
c0adf7e9 793 n->n.prefix, n->n.pxlen, e->sender->proto->name);
cfd46ee4
MM
794 return 0;
795 }
ff2857b0
OZ
796
797 c = ipa_classify_net(n->n.prefix);
798 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
421838ff 799 {
ff2857b0 800 log(L_WARN "Ignoring bogus route %I/%d received via %s",
c0adf7e9 801 n->n.prefix, n->n.pxlen, e->sender->proto->name);
ff2857b0 802 return 0;
421838ff 803 }
ff2857b0 804
84cac51a
OZ
805 if ((e->attrs->dest == RTD_MULTIPATH) && !mpnh_is_sorted(e->attrs->nexthops))
806 {
807 log(L_WARN "Ignoring unsorted multipath route %I/%d received via %s",
808 n->n.prefix, n->n.pxlen, e->sender->proto->name);
809 return 0;
810 }
811
421838ff
MM
812 return 1;
813}
814
58740ed4
MM
815/**
816 * rte_free - delete a &rte
817 * @e: &rte to be deleted
818 *
819 * rte_free() deletes the given &rte from the routing table it's linked to.
820 */
04925e90 821void
2326b001 822rte_free(rte *e)
04925e90 823{
094d2bdb 824 if (rta_is_cached(e->attrs))
04925e90
MM
825 rta_free(e->attrs);
826 sl_free(rte_slab, e);
827}
828
829static inline void
830rte_free_quick(rte *e)
2326b001
MM
831{
832 rta_free(e->attrs);
833 sl_free(rte_slab, e);
834}
835
67be5b23
MM
836static int
837rte_same(rte *x, rte *y)
838{
839 return
840 x->attrs == y->attrs &&
841 x->flags == y->flags &&
842 x->pflags == y->pflags &&
843 x->pref == y->pref &&
094d2bdb 844 (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y));
67be5b23
MM
845}
846
70577529
OZ
847static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
848
e2dc2f30 849static void
db027a41 850rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
2326b001 851{
c0adf7e9
OZ
852 struct proto *p = ah->proto;
853 struct rtable *table = ah->table;
854 struct proto_stats *stats = ah->stats;
1123e707 855 static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
00a09f3c 856 rte *before_old = NULL;
2326b001
MM
857 rte *old_best = net->routes;
858 rte *old = NULL;
00a09f3c 859 rte **k;
2326b001
MM
860
861 k = &net->routes; /* Find and remove original route from the same protocol */
862 while (old = *k)
863 {
094d2bdb 864 if (old->attrs->src == src)
2326b001 865 {
11787b84
OZ
866 /* If there is the same route in the routing table but from
867 * a different sender, then there are two paths from the
868 * source protocol to this routing table through transparent
869 * pipes, which is not allowed.
870 *
871 * We log that and ignore the route. If it is withdraw, we
872 * ignore it completely (there might be 'spurious withdraws',
873 * see FIXME in do_rte_announce())
874 */
c0adf7e9 875 if (old->sender->proto != p)
11787b84
OZ
876 {
877 if (new)
878 {
548c329c 879 log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %I/%d to table %s",
11787b84
OZ
880 net->n.prefix, net->n.pxlen, table->name);
881 rte_free_quick(new);
882 }
883 return;
884 }
885
0b761098 886 if (new && rte_same(old, new))
67be5b23
MM
887 {
888 /* No changes, ignore the new route */
cf98be7b 889
15550957 890 if (!rte_is_filtered(new))
cf98be7b
OZ
891 {
892 stats->imp_updates_ignored++;
893 rte_trace_in(D_ROUTES, p, new, "ignored");
894 }
895
67be5b23 896 rte_free_quick(new);
67be5b23
MM
897 return;
898 }
2326b001
MM
899 *k = old->next;
900 break;
901 }
902 k = &old->next;
00a09f3c 903 before_old = old;
2326b001
MM
904 }
905
00a09f3c
OZ
906 if (!old)
907 before_old = NULL;
908
925fe2d3
OZ
909 if (!old && !new)
910 {
9db74169 911 stats->imp_withdraws_ignored++;
925fe2d3
OZ
912 return;
913 }
914
b662290f
OZ
915 int new_ok = rte_is_ok(new);
916 int old_ok = rte_is_ok(old);
917
918 struct proto_limit *l = ah->rx_limit;
7d0a31de 919 if (l && !old && new)
ebecb6f6 920 {
15550957 921 u32 all_routes = stats->imp_routes + stats->filt_routes;
cf98be7b
OZ
922
923 if (all_routes >= l->limit)
b662290f 924 proto_notify_limit(ah, l, PLD_RX, all_routes);
7d0a31de
OZ
925
926 if (l->state == PLS_BLOCKED)
927 {
b662290f
OZ
928 /* In receive limit the situation is simple, old is NULL so
929 we just free new and exit like nothing happened */
930
7d0a31de
OZ
931 stats->imp_updates_ignored++;
932 rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
933 rte_free_quick(new);
934 return;
935 }
ebecb6f6
OZ
936 }
937
b662290f
OZ
938 l = ah->in_limit;
939 if (l && !old_ok && new_ok)
940 {
941 if (stats->imp_routes >= l->limit)
942 proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
943
944 if (l->state == PLS_BLOCKED)
945 {
946 /* In import limit the situation is more complicated. We
947 shouldn't just drop the route, we should handle it like
948 it was filtered. We also have to continue the route
949 processing if old or new is non-NULL, but we should exit
950 if both are NULL as this case is probably assumed to be
951 already handled. */
952
953 stats->imp_updates_ignored++;
954 rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
955
956 if (ah->in_keep_filtered)
957 new->flags |= REF_FILTERED;
958 else
959 { rte_free_quick(new); new = NULL; }
960
961 /* Note that old && !new could be possible when
962 ah->in_keep_filtered changed in the recent past. */
963
964 if (!old && !new)
965 return;
966
967 new_ok = 0;
968 goto skip_stats1;
969 }
970 }
70577529
OZ
971
972 if (new_ok)
9db74169 973 stats->imp_updates_accepted++;
70577529 974 else if (old_ok)
9db74169 975 stats->imp_withdraws_accepted++;
70577529
OZ
976 else
977 stats->imp_withdraws_ignored++;
925fe2d3 978
b662290f 979 skip_stats1:
925fe2d3
OZ
980
981 if (new)
15550957 982 rte_is_filtered(new) ? stats->filt_routes++ : stats->imp_routes++;
925fe2d3 983 if (old)
15550957 984 rte_is_filtered(old) ? stats->filt_routes-- : stats->imp_routes--;
925fe2d3 985
26822d8f 986 if (table->config->sorted)
2326b001 987 {
26822d8f
OZ
988 /* If routes are sorted, just insert new route to appropriate position */
989 if (new)
990 {
991 if (before_old && !rte_better(new, before_old))
992 k = &before_old->next;
993 else
994 k = &net->routes;
c0973621 995
26822d8f
OZ
996 for (; *k; k=&(*k)->next)
997 if (rte_better(new, *k))
998 break;
c0973621 999
26822d8f
OZ
1000 new->next = *k;
1001 *k = new;
1002 }
2326b001 1003 }
26822d8f 1004 else
2326b001 1005 {
26822d8f
OZ
1006 /* If routes are not sorted, find the best route and move it on
1007 the first position. There are several optimized cases. */
1008
094d2bdb 1009 if (src->proto->rte_recalculate && src->proto->rte_recalculate(table, net, new, old, old_best))
26822d8f
OZ
1010 goto do_recalculate;
1011
1012 if (new && rte_better(new, old_best))
2326b001 1013 {
26822d8f
OZ
1014 /* The first case - the new route is cleary optimal,
1015 we link it at the first position */
1016
c0973621
OZ
1017 new->next = net->routes;
1018 net->routes = new;
1019 }
26822d8f 1020 else if (old == old_best)
c0973621 1021 {
26822d8f
OZ
1022 /* The second case - the old best route disappeared, we add the
1023 new route (if we have any) to the list (we don't care about
1024 position) and then we elect the new optimal route and relink
1025 that route at the first position and announce it. New optimal
1026 route might be NULL if there is no more routes */
1027
1028 do_recalculate:
1029 /* Add the new route to the list */
1030 if (new)
2326b001 1031 {
26822d8f
OZ
1032 new->next = net->routes;
1033 net->routes = new;
1034 }
1035
1036 /* Find a new optimal route (if there is any) */
1037 if (net->routes)
1038 {
1039 rte **bp = &net->routes;
1040 for (k=&(*bp)->next; *k; k=&(*k)->next)
1041 if (rte_better(*k, *bp))
1042 bp = k;
1043
1044 /* And relink it */
1045 rte *best = *bp;
1046 *bp = best->next;
1047 best->next = net->routes;
1048 net->routes = best;
2326b001 1049 }
2326b001 1050 }
26822d8f
OZ
1051 else if (new)
1052 {
1053 /* The third case - the new route is not better than the old
1054 best route (therefore old_best != NULL) and the old best
1055 route was not removed (therefore old_best == net->routes).
1056 We just link the new route after the old best route. */
1057
1058 ASSERT(net->routes != NULL);
1059 new->next = net->routes->next;
1060 net->routes->next = new;
1061 }
1062 /* The fourth (empty) case - suboptimal route was removed, nothing to do */
2326b001 1063 }
c0973621 1064
26822d8f
OZ
1065 if (new)
1066 new->lastmod = now;
1067
1068 /* Log the route change */
70577529 1069 if (p->debug & D_ROUTES)
e8b29bdc 1070 {
70577529
OZ
1071 if (new_ok)
1072 rte_trace(p, new, '>', new == net->routes ? "added [best]" : "added");
1073 else if (old_ok)
1074 {
1075 if (old != old_best)
1076 rte_trace(p, old, '>', "removed");
1077 else if (rte_is_ok(net->routes))
1078 rte_trace(p, old, '>', "removed [replaced]");
1079 else
1080 rte_trace(p, old, '>', "removed [sole]");
1081 }
c0973621
OZ
1082 }
1083
26822d8f 1084 /* Propagate the route change */
8d9eef17 1085 rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL);
26822d8f 1086 if (net->routes != old_best)
8d9eef17 1087 rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL);
26822d8f 1088 if (table->config->sorted)
8d9eef17
OZ
1089 rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old);
1090 rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL);
00a09f3c
OZ
1091
1092 if (!net->routes &&
1093 (table->gc_counter++ >= table->config->gc_max_ops) &&
1094 (table->gc_time + table->config->gc_min_time <= now))
1095 rt_schedule_gc(table);
1096
70577529
OZ
1097 if (old_ok && p->rte_remove)
1098 p->rte_remove(net, old);
1099 if (new_ok && p->rte_insert)
1100 p->rte_insert(net, new);
1101
2326b001 1102 if (old)
70577529 1103 rte_free_quick(old);
5b22683d
MM
1104}
1105
e2dc2f30
MM
1106static int rte_update_nest_cnt; /* Nesting counter to allow recursive updates */
1107
1108static inline void
1109rte_update_lock(void)
1110{
1111 rte_update_nest_cnt++;
1112}
1113
1114static inline void
1115rte_update_unlock(void)
1116{
1117 if (!--rte_update_nest_cnt)
1118 lp_flush(rte_update_pool);
1119}
1120
fad04c75
OZ
1121static inline void
1122rte_hide_dummy_routes(net *net, rte **dummy)
1123{
1124 if (net->routes && net->routes->attrs->source == RTS_DUMMY)
1125 {
1126 *dummy = net->routes;
1127 net->routes = (*dummy)->next;
1128 }
1129}
1130
1131static inline void
1132rte_unhide_dummy_routes(net *net, rte **dummy)
1133{
1134 if (*dummy)
1135 {
1136 (*dummy)->next = net->routes;
1137 net->routes = *dummy;
1138 }
1139}
1140
58740ed4
MM
1141/**
1142 * rte_update - enter a new update to a routing table
1143 * @table: table to be updated
c0adf7e9 1144 * @ah: pointer to table announce hook
58740ed4
MM
1145 * @net: network node
1146 * @p: protocol submitting the update
f98e2915 1147 * @src: protocol originating the update
58740ed4
MM
1148 * @new: a &rte representing the new route or %NULL for route removal.
1149 *
1150 * This function is called by the routing protocols whenever they discover
1151 * a new route or wish to update/remove an existing route. The right announcement
2e9b2421 1152 * sequence is to build route attributes first (either un-cached with @aflags set
58740ed4
MM
1153 * to zero or a cached one using rta_lookup(); in this case please note that
1154 * you need to increase the use count of the attributes yourself by calling
1155 * rta_clone()), call rte_get_temp() to obtain a temporary &rte, fill in all
1156 * the appropriate data and finally submit the new &rte by calling rte_update().
1157 *
f98e2915
OZ
1158 * @src specifies the protocol that originally created the route and the meaning
1159 * of protocol-dependent data of @new. If @new is not %NULL, @src have to be the
1160 * same value as @new->attrs->proto. @p specifies the protocol that called
1161 * rte_update(). In most cases it is the same protocol as @src. rte_update()
1162 * stores @p in @new->sender;
1163 *
9a8f20fc
MM
1164 * When rte_update() gets any route, it automatically validates it (checks,
1165 * whether the network and next hop address are valid IP addresses and also
1166 * whether a normal routing protocol doesn't try to smuggle a host or link
1167 * scope route to the table), converts all protocol dependent attributes stored
1168 * in the &rte to temporary extended attributes, consults import filters of the
1169 * protocol to see if the route should be accepted and/or its attributes modified,
1170 * stores the temporary attributes back to the &rte.
1171 *
1172 * Now, having a "public" version of the route, we
f98e2915 1173 * automatically find any old route defined by the protocol @src
58740ed4
MM
1174 * for network @n, replace it by the new one (or removing it if @new is %NULL),
1175 * recalculate the optimal route for this destination and finally broadcast
9a8f20fc 1176 * the change (if any) to all routing protocols by calling rte_announce().
3ce8c610
MM
1177 *
1178 * All memory used for attribute lists and other temporary allocations is taken
1179 * from a special linear pool @rte_update_pool and freed when rte_update()
1180 * finishes.
58740ed4 1181 */
23ac9e9a
OZ
1182
1183void
094d2bdb 1184rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
e2dc2f30 1185{
c0adf7e9
OZ
1186 struct proto *p = ah->proto;
1187 struct proto_stats *stats = ah->stats;
1188 struct filter *filter = ah->in_filter;
e2dc2f30 1189 ea_list *tmpa = NULL;
fad04c75 1190 rte *dummy = NULL;
e2dc2f30
MM
1191
1192 rte_update_lock();
1193 if (new)
1194 {
c0adf7e9 1195 new->sender = ah;
40b65f94 1196
9db74169 1197 stats->imp_updates_received++;
cfd46ee4
MM
1198 if (!rte_validate(new))
1199 {
1200 rte_trace_in(D_FILTERS, p, new, "invalid");
9db74169 1201 stats->imp_updates_invalid++;
cfd46ee4
MM
1202 goto drop;
1203 }
cf98be7b 1204
40b65f94 1205 if (filter == FILTER_REJECT)
cfd46ee4 1206 {
9db74169 1207 stats->imp_updates_filtered++;
cfd46ee4 1208 rte_trace_in(D_FILTERS, p, new, "filtered out");
094d2bdb 1209
15550957 1210 if (! ah->in_keep_filtered)
cf98be7b
OZ
1211 goto drop;
1212
1213 /* new is a private copy, i could modify it */
15550957 1214 new->flags |= REF_FILTERED;
cfd46ee4 1215 }
cf98be7b 1216 else
e2dc2f30 1217 {
f2dd602f 1218 tmpa = rte_make_tmp_attrs(new, rte_update_pool);
cf98be7b 1219 if (filter && (filter != FILTER_REJECT))
cfd46ee4 1220 {
cf98be7b
OZ
1221 ea_list *old_tmpa = tmpa;
1222 int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0);
1223 if (fr > F_ACCEPT)
1224 {
1225 stats->imp_updates_filtered++;
1226 rte_trace_in(D_FILTERS, p, new, "filtered out");
1227
15550957 1228 if (! ah->in_keep_filtered)
cf98be7b
OZ
1229 goto drop;
1230
15550957 1231 new->flags |= REF_FILTERED;
cf98be7b 1232 }
736e143f
OZ
1233 if (tmpa != old_tmpa && src->proto->store_tmp_attrs)
1234 src->proto->store_tmp_attrs(new, tmpa);
cfd46ee4 1235 }
e2dc2f30 1236 }
094d2bdb 1237 if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
e2dc2f30
MM
1238 new->attrs = rta_lookup(new->attrs);
1239 new->flags |= REF_COW;
1240 }
925fe2d3 1241 else
094d2bdb
OZ
1242 {
1243 stats->imp_withdraws_received++;
1244
1245 if (!net || !src)
1246 {
1247 stats->imp_withdraws_ignored++;
1248 rte_update_unlock();
1249 return;
1250 }
1251 }
925fe2d3 1252
fad04c75
OZ
1253 recalc:
1254 rte_hide_dummy_routes(net, &dummy);
db027a41 1255 rte_recalculate(ah, net, new, src);
fad04c75 1256 rte_unhide_dummy_routes(net, &dummy);
e2dc2f30
MM
1257 rte_update_unlock();
1258 return;
1259
fad04c75 1260 drop:
e2dc2f30 1261 rte_free(new);
fad04c75 1262 new = NULL;
fad04c75 1263 goto recalc;
e2dc2f30
MM
1264}
1265
cfe34a31
OZ
1266/* Independent call to rte_announce(), used from next hop
1267 recalculation, outside of rte_update(). new must be non-NULL */
1268static inline void
8d9eef17
OZ
1269rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old,
1270 rte *new_best, rte *old_best)
cfe34a31 1271{
cfe34a31 1272 rte_update_lock();
8d9eef17 1273 rte_announce(tab, type, net, new, old, new_best, old_best, NULL);
cfe34a31
OZ
1274 rte_update_unlock();
1275}
1276
3e236955
JMM
1277static inline void
1278rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
5b22683d 1279{
e2dc2f30 1280 rte_update_lock();
db027a41 1281 rte_recalculate(old->sender, old->net, NULL, old->attrs->src);
e2dc2f30 1282 rte_update_unlock();
2326b001
MM
1283}
1284
36da2857
OZ
1285/* Check rtable for best route to given net whether it would be exported do p */
1286int
1287rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter)
1288{
1289 net *n = net_find(t, prefix, pxlen);
1290 rte *rt = n ? n->routes : NULL;
1291
1292 if (!rte_is_valid(rt))
1293 return 0;
1294
1295 rte_update_lock();
1296
1297 /* Rest is stripped down export_filter() */
f2dd602f 1298 ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool);
36da2857
OZ
1299 int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0;
1300 if (v == RIC_PROCESS)
1301 v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
1302
1303 /* Discard temporary rte */
1304 if (rt != n->routes)
1305 rte_free(rt);
1306
1307 rte_update_unlock();
1308
1309 return v > 0;
1310}
1311
6eda3f13
OZ
1312
1313/**
1314 * rt_refresh_begin - start a refresh cycle
1315 * @t: related routing table
1316 * @ah: related announce hook
1317 *
1318 * This function starts a refresh cycle for given routing table and announce
1319 * hook. The refresh cycle is a sequence where the protocol sends all its valid
1320 * routes to the routing table (by rte_update()). After that, all protocol
1321 * routes (more precisely routes with @ah as @sender) not sent during the
1322 * refresh cycle but still in the table from the past are pruned. This is
1323 * implemented by marking all related routes as stale by REF_STALE flag in
1324 * rt_refresh_begin(), then marking all related stale routes with REF_DISCARD
1325 * flag in rt_refresh_end() and then removing such routes in the prune loop.
1326 */
0c791f87
OZ
1327void
1328rt_refresh_begin(rtable *t, struct announce_hook *ah)
1329{
1330 net *n;
1331 rte *e;
1332
1333 FIB_WALK(&t->fib, fn)
1334 {
1335 n = (net *) fn;
1336 for (e = n->routes; e; e = e->next)
1337 if (e->sender == ah)
1338 e->flags |= REF_STALE;
1339 }
1340 FIB_WALK_END;
1341}
1342
6eda3f13
OZ
1343/**
1344 * rt_refresh_end - end a refresh cycle
1345 * @t: related routing table
1346 * @ah: related announce hook
1347 *
1348 * This function starts a refresh cycle for given routing table and announce
1349 * hook. See rt_refresh_begin() for description of refresh cycles.
1350 */
0c791f87
OZ
1351void
1352rt_refresh_end(rtable *t, struct announce_hook *ah)
1353{
1354 int prune = 0;
1355 net *n;
1356 rte *e;
1357
1358 FIB_WALK(&t->fib, fn)
1359 {
1360 n = (net *) fn;
1361 for (e = n->routes; e; e = e->next)
1362 if ((e->sender == ah) && (e->flags & REF_STALE))
1363 {
1364 e->flags |= REF_DISCARD;
1365 prune = 1;
1366 }
1367 }
1368 FIB_WALK_END;
1369
1370 if (prune)
1371 rt_schedule_prune(t);
1372}
1373
1374
58740ed4
MM
1375/**
1376 * rte_dump - dump a route
1377 * @e: &rte to be dumped
1378 *
1379 * This functions dumps contents of a &rte to debug output.
1380 */
2326b001 1381void
a0762910 1382rte_dump(rte *e)
2326b001 1383{
a0762910 1384 net *n = e->net;
47c447c4 1385 debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
c10421d3 1386 debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
0cdbd397 1387 rta_dump(e->attrs);
094d2bdb
OZ
1388 if (e->attrs->src->proto->proto->dump_attrs)
1389 e->attrs->src->proto->proto->dump_attrs(e);
0cdbd397 1390 debug("\n");
2326b001 1391}
62aa008a 1392
58740ed4
MM
1393/**
1394 * rt_dump - dump a routing table
1395 * @t: routing table to be dumped
1396 *
1397 * This function dumps contents of a given routing table to debug output.
1398 */
2326b001
MM
1399void
1400rt_dump(rtable *t)
1401{
0cdbd397
MM
1402 rte *e;
1403 net *n;
0e02abfd 1404 struct announce_hook *a;
0cdbd397
MM
1405
1406 debug("Dump of routing table <%s>\n", t->name);
e440395d 1407#ifdef DEBUGGING
08e2d625 1408 fib_check(&t->fib);
e440395d 1409#endif
08e2d625
MM
1410 FIB_WALK(&t->fib, fn)
1411 {
1412 n = (net *) fn;
1413 for(e=n->routes; e; e=e->next)
1414 rte_dump(e);
0cdbd397 1415 }
08e2d625 1416 FIB_WALK_END;
0e02abfd
MM
1417 WALK_LIST(a, t->hooks)
1418 debug("\tAnnounces routes to protocol %s\n", a->proto->name);
0cdbd397 1419 debug("\n");
2326b001 1420}
62aa008a 1421
58740ed4
MM
1422/**
1423 * rt_dump_all - dump all routing tables
1424 *
1425 * This function dumps contents of all routing tables to debug output.
1426 */
6d45cf21
MM
1427void
1428rt_dump_all(void)
1429{
0e02abfd
MM
1430 rtable *t;
1431
1432 WALK_LIST(t, routing_tables)
1433 rt_dump(t);
6d45cf21
MM
1434}
1435
0c791f87
OZ
1436static inline void
1437rt_schedule_prune(rtable *tab)
1438{
1439 rt_mark_for_prune(tab);
1440 ev_schedule(tab->rt_event);
1441}
1442
cfe34a31
OZ
1443static inline void
1444rt_schedule_gc(rtable *tab)
1445{
1446 if (tab->gc_scheduled)
1447 return;
1448
1449 tab->gc_scheduled = 1;
1450 ev_schedule(tab->rt_event);
1451}
1452
1453static inline void
1454rt_schedule_hcu(rtable *tab)
1455{
1456 if (tab->hcu_scheduled)
1457 return;
1458
1459 tab->hcu_scheduled = 1;
1460 ev_schedule(tab->rt_event);
1461}
1462
1463static inline void
1464rt_schedule_nhu(rtable *tab)
1465{
1466 if (tab->nhu_state == 0)
1467 ev_schedule(tab->rt_event);
1468
1469 /* state change 0->1, 2->3 */
1470 tab->nhu_state |= 1;
1471}
1472
0c791f87 1473
fb829de6
OZ
1474static void
1475rt_prune_nets(rtable *tab)
1476{
1477 struct fib_iterator fit;
1478 int ncnt = 0, ndel = 0;
1479
1480#ifdef DEBUGGING
1481 fib_check(&tab->fib);
1482#endif
1483
1484 FIB_ITERATE_INIT(&fit, &tab->fib);
1485again:
1486 FIB_ITERATE_START(&tab->fib, &fit, f)
1487 {
1488 net *n = (net *) f;
1489 ncnt++;
1490 if (!n->routes) /* Orphaned FIB entry */
1491 {
1492 FIB_ITERATE_PUT(&fit, f);
1493 fib_delete(&tab->fib, f);
1494 ndel++;
1495 goto again;
1496 }
1497 }
1498 FIB_ITERATE_END(f);
1499 DBG("Pruned %d of %d networks\n", ndel, ncnt);
1500
1501 tab->gc_counter = 0;
1502 tab->gc_time = now;
1503 tab->gc_scheduled = 0;
1504}
1505
8f6accb5 1506static void
cfe34a31 1507rt_event(void *ptr)
5996da6a 1508{
cfe34a31
OZ
1509 rtable *tab = ptr;
1510
1511 if (tab->hcu_scheduled)
1512 rt_update_hostcache(tab);
0e02abfd 1513
cfe34a31
OZ
1514 if (tab->nhu_state)
1515 rt_next_hop_update(tab);
1516
0c791f87
OZ
1517 if (tab->prune_state)
1518 if (!rt_prune_table(tab))
1519 {
1520 /* Table prune unfinished */
1521 ev_schedule(tab->rt_event);
1522 return;
1523 }
1524
cfe34a31 1525 if (tab->gc_scheduled)
094d2bdb
OZ
1526 {
1527 rt_prune_nets(tab);
1528 rt_prune_sources(); // FIXME this should be moved to independent event
1529 }
5996da6a
MM
1530}
1531
b9626ec6
MM
1532void
1533rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
1534{
1535 bzero(t, sizeof(*t));
1536 fib_init(&t->fib, p, sizeof(net), 0, rte_init);
1537 t->name = name;
1538 t->config = cf;
1539 init_list(&t->hooks);
1540 if (cf)
1541 {
cfe34a31
OZ
1542 t->rt_event = ev_new(p);
1543 t->rt_event->hook = rt_event;
1544 t->rt_event->data = t;
2eca3b3a 1545 t->gc_time = now;
b9626ec6
MM
1546 }
1547}
1548
58740ed4
MM
1549/**
1550 * rt_init - initialize routing tables
1551 *
1552 * This function is called during BIRD startup. It initializes the
1553 * routing table module.
1554 */
2326b001
MM
1555void
1556rt_init(void)
1557{
1558 rta_init();
5996da6a 1559 rt_table_pool = rp_new(&root_pool, "Routing tables");
e2dc2f30 1560 rte_update_pool = lp_new(rt_table_pool, 4080);
5996da6a 1561 rte_slab = sl_new(rt_table_pool, sizeof(rte));
0e02abfd 1562 init_list(&routing_tables);
2326b001 1563}
1a54b1c6 1564
fb829de6 1565
0c791f87 1566static int
d0e23d42 1567rt_prune_step(rtable *tab, int *limit)
fb829de6
OZ
1568{
1569 struct fib_iterator *fit = &tab->prune_fit;
1a54b1c6
MM
1570
1571 DBG("Pruning route table %s\n", tab->name);
0521e4f6
MM
1572#ifdef DEBUGGING
1573 fib_check(&tab->fib);
1574#endif
fb829de6 1575
0c791f87 1576 if (tab->prune_state == RPS_NONE)
fb829de6
OZ
1577 return 1;
1578
0c791f87 1579 if (tab->prune_state == RPS_SCHEDULED)
fb829de6
OZ
1580 {
1581 FIB_ITERATE_INIT(fit, &tab->fib);
0c791f87 1582 tab->prune_state = RPS_RUNNING;
fb829de6
OZ
1583 }
1584
08e2d625 1585again:
fb829de6 1586 FIB_ITERATE_START(&tab->fib, fit, fn)
1a54b1c6 1587 {
fb829de6 1588 net *n = (net *) fn;
08e2d625 1589 rte *e;
fb829de6 1590
08e2d625 1591 rescan:
fb829de6 1592 for (e=n->routes; e; e=e->next)
d0e23d42 1593 if (e->sender->proto->flushing || (e->flags & REF_DISCARD))
08e2d625 1594 {
0c791f87 1595 if (*limit <= 0)
fb829de6
OZ
1596 {
1597 FIB_ITERATE_PUT(fit, fn);
1598 return 0;
1599 }
1600
3e236955 1601 rte_discard(e);
0c791f87 1602 (*limit)--;
fb829de6 1603
08e2d625
MM
1604 goto rescan;
1605 }
fb829de6 1606 if (!n->routes) /* Orphaned FIB entry */
1a54b1c6 1607 {
fb829de6
OZ
1608 FIB_ITERATE_PUT(fit, fn);
1609 fib_delete(&tab->fib, fn);
08e2d625 1610 goto again;
1a54b1c6 1611 }
1a54b1c6 1612 }
fb829de6
OZ
1613 FIB_ITERATE_END(fn);
1614
0521e4f6
MM
1615#ifdef DEBUGGING
1616 fib_check(&tab->fib);
1617#endif
fb829de6 1618
0c791f87 1619 tab->prune_state = RPS_NONE;
fb829de6 1620 return 1;
1a54b1c6 1621}
0e02abfd 1622
6eda3f13
OZ
1623/**
1624 * rt_prune_table - prune a routing table
8e433d6a 1625 * @tab: a routing table for pruning
6eda3f13
OZ
1626 *
1627 * This function scans the routing table @tab and removes routes belonging to
1628 * flushing protocols, discarded routes and also stale network entries, in a
1629 * similar fashion like rt_prune_loop(). Returns 1 when all such routes are
1630 * pruned. Contrary to rt_prune_loop(), this function is not a part of the
1631 * protocol flushing loop, but it is called from rt_event() for just one routing
1632 * table.
1633 *
1634 * Note that rt_prune_table() and rt_prune_loop() share (for each table) the
1635 * prune state (@prune_state) and also the pruning iterator (@prune_fit).
1636 */
0c791f87
OZ
1637static inline int
1638rt_prune_table(rtable *tab)
1639{
1640 int limit = 512;
d0e23d42 1641 return rt_prune_step(tab, &limit);
0c791f87
OZ
1642}
1643
58740ed4 1644/**
fb829de6 1645 * rt_prune_loop - prune routing tables
58740ed4 1646 *
6eda3f13
OZ
1647 * The prune loop scans routing tables and removes routes belonging to flushing
1648 * protocols, discarded routes and also stale network entries. Returns 1 when
1649 * all such routes are pruned. It is a part of the protocol flushing loop.
58740ed4 1650 */
fb829de6
OZ
1651int
1652rt_prune_loop(void)
0e02abfd 1653{
0c791f87 1654 int limit = 512;
9135c1f0 1655 rtable *t;
0e02abfd
MM
1656
1657 WALK_LIST(t, routing_tables)
d0e23d42 1658 if (! rt_prune_step(t, &limit))
fb829de6
OZ
1659 return 0;
1660
1661 return 1;
0e02abfd
MM
1662}
1663
cfe34a31
OZ
1664void
1665rt_preconfig(struct config *c)
1666{
9b9a7143 1667 struct symbol *s = cf_get_symbol("master");
cfe34a31
OZ
1668
1669 init_list(&c->tables);
1670 c->master_rtc = rt_new_table(s);
1671}
1672
1673
1674/*
1675 * Some functions for handing internal next hop updates
1676 * triggered by rt_schedule_nhu().
1677 */
1678
cfe34a31
OZ
1679static inline int
1680rta_next_hop_outdated(rta *a)
1681{
1682 struct hostentry *he = a->hostentry;
7e95c05d
OZ
1683
1684 if (!he)
1685 return 0;
1686
1687 if (!he->src)
1688 return a->dest != RTD_UNREACHABLE;
1689
1690 return (a->iface != he->src->iface) || !ipa_equal(a->gw, he->gw) ||
1691 (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
1692 !mpnh_same(a->nexthops, he->src->nexthops);
cfe34a31
OZ
1693}
1694
1695static inline void
1696rta_apply_hostentry(rta *a, struct hostentry *he)
1697{
1698 a->hostentry = he;
7e95c05d 1699 a->iface = he->src ? he->src->iface : NULL;
cfe34a31
OZ
1700 a->gw = he->gw;
1701 a->dest = he->dest;
d1e146f2 1702 a->igp_metric = he->igp_metric;
7e95c05d 1703 a->nexthops = he->src ? he->src->nexthops : NULL;
cfe34a31
OZ
1704}
1705
1706static inline rte *
3e236955 1707rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
cfe34a31
OZ
1708{
1709 rta a;
1710 memcpy(&a, old->attrs, sizeof(rta));
1711 rta_apply_hostentry(&a, old->attrs->hostentry);
1712 a.aflags = 0;
1713
1714 rte *e = sl_alloc(rte_slab);
1715 memcpy(e, old, sizeof(rte));
1716 e->attrs = rta_lookup(&a);
1717
1718 return e;
1719}
1720
1721static inline int
1722rt_next_hop_update_net(rtable *tab, net *n)
1723{
1724 rte **k, *e, *new, *old_best, **new_best;
1725 int count = 0;
1726 int free_old_best = 0;
1727
1728 old_best = n->routes;
1729 if (!old_best)
1730 return 0;
1731
cfe34a31 1732 for (k = &n->routes; e = *k; k = &e->next)
be4cd99a
OZ
1733 if (rta_next_hop_outdated(e->attrs))
1734 {
1735 new = rt_next_hop_update_rte(tab, e);
1736 *k = new;
cfe34a31 1737
8d9eef17 1738 rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
c0adf7e9 1739 rte_trace_in(D_ROUTES, new->sender->proto, new, "updated");
cfe34a31 1740
be4cd99a
OZ
1741 /* Call a pre-comparison hook */
1742 /* Not really an efficient way to compute this */
094d2bdb
OZ
1743 if (e->attrs->src->proto->rte_recalculate)
1744 e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL);
cfe34a31 1745
be4cd99a
OZ
1746 if (e != old_best)
1747 rte_free_quick(e);
1748 else /* Freeing of the old best rte is postponed */
1749 free_old_best = 1;
cfe34a31 1750
be4cd99a
OZ
1751 e = new;
1752 count++;
1753 }
1754
1755 if (!count)
1756 return 0;
1757
1758 /* Find the new best route */
1759 new_best = NULL;
1760 for (k = &n->routes; e = *k; k = &e->next)
1761 {
cfe34a31
OZ
1762 if (!new_best || rte_better(e, *new_best))
1763 new_best = k;
1764 }
1765
1766 /* Relink the new best route to the first position */
1767 new = *new_best;
1768 if (new != n->routes)
1769 {
1770 *new_best = new->next;
1771 new->next = n->routes;
1772 n->routes = new;
1773 }
1774
1775 /* Announce the new best route */
1776 if (new != old_best)
1777 {
8d9eef17 1778 rte_announce_i(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL);
c0adf7e9 1779 rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]");
cfe34a31
OZ
1780 }
1781
8d9eef17
OZ
1782 /* FIXME: Better announcement of merged routes */
1783 rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best);
1784
d107ef78 1785 if (free_old_best)
cfe34a31
OZ
1786 rte_free_quick(old_best);
1787
1788 return count;
1789}
1790
1791static void
1792rt_next_hop_update(rtable *tab)
1793{
1794 struct fib_iterator *fit = &tab->nhu_fit;
1795 int max_feed = 32;
1796
1797 if (tab->nhu_state == 0)
1798 return;
1799
1800 if (tab->nhu_state == 1)
1801 {
1802 FIB_ITERATE_INIT(fit, &tab->fib);
1803 tab->nhu_state = 2;
1804 }
1805
1806 FIB_ITERATE_START(&tab->fib, fit, fn)
1807 {
1808 if (max_feed <= 0)
1809 {
1810 FIB_ITERATE_PUT(fit, fn);
1811 ev_schedule(tab->rt_event);
1812 return;
1813 }
1814 max_feed -= rt_next_hop_update_net(tab, (net *) fn);
1815 }
1816 FIB_ITERATE_END(fn);
1817
1818 /* state change 2->0, 3->1 */
1819 tab->nhu_state &= 1;
1820
1821 if (tab->nhu_state > 0)
1822 ev_schedule(tab->rt_event);
1823}
1824
1825
b9626ec6
MM
1826struct rtable_config *
1827rt_new_table(struct symbol *s)
1828{
36415e4b
OZ
1829 /* Hack that allows to 'redefine' the master table */
1830 if ((s->class == SYM_TABLE) && (s->def == new_config->master_rtc))
1831 return s->def;
1832
b9626ec6
MM
1833 struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
1834
1835 cf_define_symbol(s, SYM_TABLE, c);
1836 c->name = s->name;
1837 add_tail(&new_config->tables, &c->n);
2eca3b3a 1838 c->gc_max_ops = 1000;
b9626ec6
MM
1839 c->gc_min_time = 5;
1840 return c;
1841}
1842
58740ed4
MM
1843/**
1844 * rt_lock_table - lock a routing table
1845 * @r: routing table to be locked
1846 *
1847 * Lock a routing table, because it's in use by a protocol,
1848 * preventing it from being freed when it gets undefined in a new
1849 * configuration.
1850 */
0e02abfd 1851void
50fe90ed 1852rt_lock_table(rtable *r)
0e02abfd 1853{
50fe90ed
MM
1854 r->use_count++;
1855}
1856
58740ed4
MM
1857/**
1858 * rt_unlock_table - unlock a routing table
1859 * @r: routing table to be unlocked
1860 *
1861 * Unlock a routing table formerly locked by rt_lock_table(),
1862 * that is decrease its use count and delete it if it's scheduled
1863 * for deletion by configuration changes.
1864 */
50fe90ed
MM
1865void
1866rt_unlock_table(rtable *r)
1867{
1868 if (!--r->use_count && r->deleted)
1869 {
1870 struct config *conf = r->deleted;
1871 DBG("Deleting routing table %s\n", r->name);
86b4e170 1872 r->config->table = NULL;
cfe34a31
OZ
1873 if (r->hostcache)
1874 rt_free_hostcache(r);
50fe90ed
MM
1875 rem_node(&r->n);
1876 fib_free(&r->fib);
cfe34a31 1877 rfree(r->rt_event);
50fe90ed
MM
1878 mb_free(r);
1879 config_del_obstacle(conf);
1880 }
1881}
1882
58740ed4
MM
1883/**
1884 * rt_commit - commit new routing table configuration
1885 * @new: new configuration
1886 * @old: original configuration or %NULL if it's boot time config
1887 *
1888 * Scan differences between @old and @new configuration and modify
1889 * the routing tables according to these changes. If @new defines a
1890 * previously unknown table, create it, if it omits a table existing
1891 * in @old, schedule it for deletion (it gets deleted when all protocols
1892 * disconnect from it by calling rt_unlock_table()), if it exists
1893 * in both configurations, leave it unchanged.
1894 */
50fe90ed
MM
1895void
1896rt_commit(struct config *new, struct config *old)
1897{
1898 struct rtable_config *o, *r;
0e02abfd 1899
50fe90ed
MM
1900 DBG("rt_commit:\n");
1901 if (old)
0e02abfd 1902 {
50fe90ed
MM
1903 WALK_LIST(o, old->tables)
1904 {
1905 rtable *ot = o->table;
1906 if (!ot->deleted)
1907 {
9b9a7143 1908 struct symbol *sym = cf_find_symbol(new, o->name);
bf8558bc 1909 if (sym && sym->class == SYM_TABLE && !new->shutdown)
50fe90ed
MM
1910 {
1911 DBG("\t%s: same\n", o->name);
1912 r = sym->def;
1913 r->table = ot;
1914 ot->name = r->name;
b9626ec6 1915 ot->config = r;
26822d8f
OZ
1916 if (o->sorted != r->sorted)
1917 log(L_WARN "Reconfiguration of rtable sorted flag not implemented");
50fe90ed
MM
1918 }
1919 else
1920 {
bf8558bc 1921 DBG("\t%s: deleted\n", o->name);
50fe90ed
MM
1922 ot->deleted = old;
1923 config_add_obstacle(old);
1924 rt_lock_table(ot);
1925 rt_unlock_table(ot);
1926 }
1927 }
1928 }
0e02abfd 1929 }
50fe90ed
MM
1930
1931 WALK_LIST(r, new->tables)
1932 if (!r->table)
1933 {
1934 rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
1935 DBG("\t%s: created\n", r->name);
b9626ec6 1936 rt_setup(rt_table_pool, t, r->name, r);
50fe90ed
MM
1937 add_tail(&routing_tables, &t->n);
1938 r->table = t;
1939 }
1940 DBG("\tdone\n");
0e02abfd 1941}
730f2e2c 1942
23ac9e9a
OZ
1943static inline void
1944do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
1945{
23ac9e9a 1946 rte_update_lock();
00a09f3c 1947 if (type == RA_ACCEPTED)
db027a41 1948 rt_notify_accepted(h, n, e, NULL, NULL, p->refeeding ? 2 : 1);
8d9eef17
OZ
1949 else if (type == RA_MERGED)
1950 rt_notify_merged(h, n, NULL, NULL, e, p->refeeding ? e : NULL, p->refeeding);
00a09f3c 1951 else
db027a41 1952 rt_notify_basic(h, n, e, p->refeeding ? e : NULL, p->refeeding);
23ac9e9a
OZ
1953 rte_update_unlock();
1954}
1955
58740ed4
MM
1956/**
1957 * rt_feed_baby - advertise routes to a new protocol
1958 * @p: protocol to be fed
1959 *
1960 * This function performs one pass of advertisement of routes to a newly
1961 * initialized protocol. It's called by the protocol code as long as it
1962 * has something to do. (We avoid transferring all the routes in single
1963 * pass in order not to monopolize CPU time.)
1964 */
ac5d8012
MM
1965int
1966rt_feed_baby(struct proto *p)
1967{
1968 struct announce_hook *h;
1969 struct fib_iterator *fit;
76dfda9e 1970 int max_feed = 256;
ac5d8012
MM
1971
1972 if (!p->feed_ahook) /* Need to initialize first */
1973 {
1974 if (!p->ahooks)
1975 return 1;
1976 DBG("Announcing routes to new protocol %s\n", p->name);
1977 p->feed_ahook = p->ahooks;
1978 fit = p->feed_iterator = mb_alloc(p->pool, sizeof(struct fib_iterator));
1979 goto next_hook;
1980 }
1981 fit = p->feed_iterator;
1982
1983again:
1984 h = p->feed_ahook;
1985 FIB_ITERATE_START(&h->table->fib, fit, fn)
1986 {
1987 net *n = (net *) fn;
258d0ad4 1988 rte *e = n->routes;
76dfda9e
MM
1989 if (max_feed <= 0)
1990 {
1991 FIB_ITERATE_PUT(fit, fn);
1992 return 0;
1993 }
23ac9e9a 1994
cf98be7b
OZ
1995 /* XXXX perhaps we should change feed for RA_ACCEPTED to not use 'new' */
1996
b7f3df79 1997 if ((p->accept_ra_types == RA_OPTIMAL) ||
8d9eef17
OZ
1998 (p->accept_ra_types == RA_ACCEPTED) ||
1999 (p->accept_ra_types == RA_MERGED))
cf98be7b 2000 if (rte_is_valid(e))
23ac9e9a 2001 {
0c791f87 2002 if (p->export_state != ES_FEEDING)
23ac9e9a 2003 return 1; /* In the meantime, the protocol fell down. */
ca34698c 2004
b7f3df79 2005 do_feed_baby(p, p->accept_ra_types, h, n, e);
23ac9e9a
OZ
2006 max_feed--;
2007 }
2008
2009 if (p->accept_ra_types == RA_ANY)
ca34698c 2010 for(e = n->routes; e; e = e->next)
23ac9e9a 2011 {
0c791f87 2012 if (p->export_state != ES_FEEDING)
23ac9e9a 2013 return 1; /* In the meantime, the protocol fell down. */
ca34698c
OZ
2014
2015 if (!rte_is_valid(e))
2016 continue;
2017
23ac9e9a
OZ
2018 do_feed_baby(p, RA_ANY, h, n, e);
2019 max_feed--;
2020 }
ac5d8012
MM
2021 }
2022 FIB_ITERATE_END(fn);
2023 p->feed_ahook = h->next;
2024 if (!p->feed_ahook)
2025 {
2026 mb_free(p->feed_iterator);
2027 p->feed_iterator = NULL;
2028 return 1;
2029 }
2030
2031next_hook:
2032 h = p->feed_ahook;
2033 FIB_ITERATE_INIT(fit, &h->table->fib);
2034 goto again;
2035}
2036
58740ed4
MM
2037/**
2038 * rt_feed_baby_abort - abort protocol feeding
2039 * @p: protocol
2040 *
2041 * This function is called by the protocol code when the protocol
2042 * stops or ceases to exist before the last iteration of rt_feed_baby()
2043 * has finished.
2044 */
ac5d8012
MM
2045void
2046rt_feed_baby_abort(struct proto *p)
2047{
2048 if (p->feed_ahook)
2049 {
2050 /* Unlink the iterator and exit */
2051 fit_get(&p->feed_ahook->table->fib, p->feed_iterator);
2052 p->feed_ahook = NULL;
2053 }
2054}
2055
f2b76f2c
OZ
2056
2057static inline unsigned
2058ptr_hash(void *ptr)
2059{
2060 uintptr_t p = (uintptr_t) ptr;
2061 return p ^ (p << 8) ^ (p >> 16);
2062}
2063
2064static inline unsigned
2065hc_hash(ip_addr a, rtable *dep)
2066{
2067 return (ipa_hash(a) ^ ptr_hash(dep)) & 0xffff;
2068}
2069
2070static inline void
2071hc_insert(struct hostcache *hc, struct hostentry *he)
2072{
ae80a2de 2073 uint k = he->hash_key >> hc->hash_shift;
f2b76f2c
OZ
2074 he->next = hc->hash_table[k];
2075 hc->hash_table[k] = he;
2076}
2077
2078static inline void
2079hc_remove(struct hostcache *hc, struct hostentry *he)
2080{
2081 struct hostentry **hep;
ae80a2de 2082 uint k = he->hash_key >> hc->hash_shift;
f2b76f2c
OZ
2083
2084 for (hep = &hc->hash_table[k]; *hep != he; hep = &(*hep)->next);
2085 *hep = he->next;
2086}
2087
2088#define HC_DEF_ORDER 10
2089#define HC_HI_MARK *4
2090#define HC_HI_STEP 2
2091#define HC_HI_ORDER 16 /* Must be at most 16 */
2092#define HC_LO_MARK /5
2093#define HC_LO_STEP 2
2094#define HC_LO_ORDER 10
2095
2096static void
2097hc_alloc_table(struct hostcache *hc, unsigned order)
2098{
3e236955 2099 uint hsize = 1 << order;
f2b76f2c
OZ
2100 hc->hash_order = order;
2101 hc->hash_shift = 16 - order;
3e236955
JMM
2102 hc->hash_max = (order >= HC_HI_ORDER) ? ~0U : (hsize HC_HI_MARK);
2103 hc->hash_min = (order <= HC_LO_ORDER) ? 0U : (hsize HC_LO_MARK);
f2b76f2c
OZ
2104
2105 hc->hash_table = mb_allocz(rt_table_pool, hsize * sizeof(struct hostentry *));
2106}
2107
cfe34a31 2108static void
f2b76f2c 2109hc_resize(struct hostcache *hc, unsigned new_order)
cfe34a31 2110{
f2b76f2c
OZ
2111 struct hostentry **old_table = hc->hash_table;
2112 struct hostentry *he, *hen;
3e236955
JMM
2113 uint old_size = 1 << hc->hash_order;
2114 uint i;
f2b76f2c
OZ
2115
2116 hc_alloc_table(hc, new_order);
2117 for (i = 0; i < old_size; i++)
2118 for (he = old_table[i]; he != NULL; he=hen)
2119 {
2120 hen = he->next;
2121 hc_insert(hc, he);
2122 }
2123 mb_free(old_table);
2124}
2125
2126static struct hostentry *
1b180121 2127hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsigned k)
f2b76f2c
OZ
2128{
2129 struct hostentry *he = sl_alloc(hc->slab);
2130
2131 he->addr = a;
1b180121 2132 he->link = ll;
f2b76f2c
OZ
2133 he->tab = dep;
2134 he->hash_key = k;
2135 he->uc = 0;
7e95c05d 2136 he->src = NULL;
f2b76f2c
OZ
2137
2138 add_tail(&hc->hostentries, &he->ln);
2139 hc_insert(hc, he);
2140
2141 hc->hash_items++;
2142 if (hc->hash_items > hc->hash_max)
2143 hc_resize(hc, hc->hash_order + HC_HI_STEP);
2144
2145 return he;
2146}
2147
2148static void
2149hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)
2150{
7e95c05d
OZ
2151 rta_free(he->src);
2152
f2b76f2c
OZ
2153 rem_node(&he->ln);
2154 hc_remove(hc, he);
2155 sl_free(hc->slab, he);
2156
2157 hc->hash_items--;
2158 if (hc->hash_items < hc->hash_min)
2159 hc_resize(hc, hc->hash_order - HC_LO_STEP);
cfe34a31
OZ
2160}
2161
2162static void
2163rt_init_hostcache(rtable *tab)
2164{
2165 struct hostcache *hc = mb_allocz(rt_table_pool, sizeof(struct hostcache));
2166 init_list(&hc->hostentries);
f2b76f2c
OZ
2167
2168 hc->hash_items = 0;
2169 hc_alloc_table(hc, HC_DEF_ORDER);
2170 hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
2171
c477f489 2172 hc->lp = lp_new(rt_table_pool, 1008);
51762a45 2173 hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
c477f489 2174
cfe34a31
OZ
2175 tab->hostcache = hc;
2176}
2177
2178static void
2179rt_free_hostcache(rtable *tab)
2180{
2181 struct hostcache *hc = tab->hostcache;
2182
2183 node *n;
2184 WALK_LIST(n, hc->hostentries)
2185 {
2186 struct hostentry *he = SKIP_BACK(struct hostentry, ln, n);
7e95c05d
OZ
2187 rta_free(he->src);
2188
cfe34a31
OZ
2189 if (he->uc)
2190 log(L_ERR "Hostcache is not empty in table %s", tab->name);
2191 }
2192
f2b76f2c 2193 rfree(hc->slab);
c477f489 2194 rfree(hc->lp);
f2b76f2c 2195 mb_free(hc->hash_table);
cfe34a31
OZ
2196 mb_free(hc);
2197}
2198
2199static void
2200rt_notify_hostcache(rtable *tab, net *net)
2201{
2202 struct hostcache *hc = tab->hostcache;
2203
2204 if (tab->hcu_scheduled)
2205 return;
2206
c477f489
OZ
2207 if (trie_match_prefix(hc->trie, net->n.prefix, net->n.pxlen))
2208 rt_schedule_hcu(tab);
cfe34a31
OZ
2209}
2210
2211static int
2212if_local_addr(ip_addr a, struct iface *i)
2213{
2214 struct ifa *b;
2215
2216 WALK_LIST(b, i->addrs)
2217 if (ipa_equal(a, b->ip))
2218 return 1;
2219
2220 return 0;
2221}
2222
d1e146f2
OZ
2223static u32
2224rt_get_igp_metric(rte *rt)
2225{
ba5e5940
OZ
2226 eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
2227
2228 if (ea)
2229 return ea->u.data;
2230
d1e146f2 2231 rta *a = rt->attrs;
b7c48981
OF
2232
2233#ifdef CONFIG_OSPF
d1e146f2
OZ
2234 if ((a->source == RTS_OSPF) ||
2235 (a->source == RTS_OSPF_IA) ||
2236 (a->source == RTS_OSPF_EXT1))
2237 return rt->u.ospf.metric1;
b7c48981 2238#endif
d1e146f2 2239
b7c48981 2240#ifdef CONFIG_RIP
d1e146f2
OZ
2241 if (a->source == RTS_RIP)
2242 return rt->u.rip.metric;
b7c48981 2243#endif
d1e146f2
OZ
2244
2245 /* Device routes */
7e95c05d 2246 if ((a->dest != RTD_ROUTER) && (a->dest != RTD_MULTIPATH))
d1e146f2
OZ
2247 return 0;
2248
2249 return IGP_METRIC_UNKNOWN;
2250}
2251
cfe34a31
OZ
2252static int
2253rt_update_hostentry(rtable *tab, struct hostentry *he)
2254{
7e95c05d 2255 rta *old_src = he->src;
c477f489 2256 int pxlen = 0;
cfe34a31 2257
7e95c05d
OZ
2258 /* Reset the hostentry */
2259 he->src = NULL;
2260 he->gw = IPA_NONE;
2261 he->dest = RTD_UNREACHABLE;
2262 he->igp_metric = 0;
2263
d1e146f2
OZ
2264 net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH);
2265 if (n)
cfe34a31 2266 {
cf98be7b
OZ
2267 rte *e = n->routes;
2268 rta *a = e->attrs;
c477f489 2269 pxlen = n->n.pxlen;
cfe34a31 2270
2c9033af
OZ
2271 if (a->hostentry)
2272 {
2273 /* Recursive route should not depend on another recursive route */
2274 log(L_WARN "Next hop address %I resolvable through recursive route for %I/%d",
7e95c05d
OZ
2275 he->addr, n->n.prefix, pxlen);
2276 goto done;
2c9033af 2277 }
7e95c05d
OZ
2278
2279 if (a->dest == RTD_DEVICE)
cfe34a31 2280 {
f2b76f2c 2281 if (if_local_addr(he->addr, a->iface))
cfe34a31
OZ
2282 {
2283 /* The host address is a local address, this is not valid */
2284 log(L_WARN "Next hop address %I is a local address of iface %s",
f2b76f2c 2285 he->addr, a->iface->name);
7e95c05d 2286 goto done;
cfe34a31 2287 }
7e95c05d
OZ
2288
2289 /* The host is directly reachable, use link as a gateway */
2290 he->gw = he->link;
2291 he->dest = RTD_ROUTER;
cfe34a31
OZ
2292 }
2293 else
2294 {
2295 /* The host is reachable through some route entry */
cfe34a31
OZ
2296 he->gw = a->gw;
2297 he->dest = a->dest;
2298 }
d1e146f2 2299
7e95c05d 2300 he->src = rta_clone(a);
cf98be7b 2301 he->igp_metric = rt_get_igp_metric(e);
cfe34a31
OZ
2302 }
2303
7e95c05d 2304 done:
c477f489
OZ
2305 /* Add a prefix range to the trie */
2306 trie_add_prefix(tab->hostcache->trie, he->addr, MAX_PREFIX_LENGTH, pxlen, MAX_PREFIX_LENGTH);
2307
7e95c05d
OZ
2308 rta_free(old_src);
2309 return old_src != he->src;
cfe34a31
OZ
2310}
2311
2312static void
2313rt_update_hostcache(rtable *tab)
2314{
2315 struct hostcache *hc = tab->hostcache;
2316 struct hostentry *he;
2317 node *n, *x;
2318
c477f489
OZ
2319 /* Reset the trie */
2320 lp_flush(hc->lp);
51762a45 2321 hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
c477f489 2322
cfe34a31
OZ
2323 WALK_LIST_DELSAFE(n, x, hc->hostentries)
2324 {
2325 he = SKIP_BACK(struct hostentry, ln, n);
2326 if (!he->uc)
2327 {
f2b76f2c 2328 hc_delete_hostentry(hc, he);
cfe34a31
OZ
2329 continue;
2330 }
2331
2332 if (rt_update_hostentry(tab, he))
2333 rt_schedule_nhu(he->tab);
2334 }
2335
2336 tab->hcu_scheduled = 0;
2337}
2338
2339static struct hostentry *
094d2bdb 2340rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
cfe34a31
OZ
2341{
2342 struct hostentry *he;
2343
2344 if (!tab->hostcache)
2345 rt_init_hostcache(tab);
2346
ae80a2de 2347 uint k = hc_hash(a, dep);
f2b76f2c
OZ
2348 struct hostcache *hc = tab->hostcache;
2349 for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next)
2350 if (ipa_equal(he->addr, a) && (he->tab == dep))
2351 return he;
cfe34a31 2352
1b180121 2353 he = hc_new_hostentry(hc, a, ll, dep, k);
f2b76f2c 2354 rt_update_hostentry(tab, he);
cfe34a31
OZ
2355 return he;
2356}
2357
2358void
1b180121 2359rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll)
cfe34a31 2360{
094d2bdb 2361 rta_apply_hostentry(a, rt_get_hostentry(tab, *gw, *ll, dep));
cfe34a31
OZ
2362}
2363
094d2bdb 2364
730f2e2c
MM
2365/*
2366 * CLI commands
2367 */
2368
6887f409
OF
2369static byte *
2370rt_format_via(rte *e)
730f2e2c 2371{
730f2e2c
MM
2372 rta *a = e->attrs;
2373
6887f409
OF
2374 /* Max text length w/o IP addr and interface name is 16 */
2375 static byte via[STD_ADDRESS_P_LENGTH+sizeof(a->iface->name)+16];
2376
730f2e2c
MM
2377 switch (a->dest)
2378 {
2379 case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break;
2380 case RTD_DEVICE: bsprintf(via, "dev %s", a->iface->name); break;
2381 case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break;
2382 case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
2383 case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
7e95c05d 2384 case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
730f2e2c
MM
2385 default: bsprintf(via, "???");
2386 }
6887f409 2387 return via;
cfd46ee4
MM
2388}
2389
2390static void
ce1da96e 2391rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa)
cfd46ee4 2392{
6887f409 2393 byte from[STD_ADDRESS_P_LENGTH+8];
c37e7851 2394 byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
cfd46ee4 2395 rta *a = e->attrs;
5a56f27c 2396 int primary = (e->net->routes == e);
32f95476 2397 int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
094d2bdb 2398 void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
7e95c05d 2399 struct mpnh *nh;
cfd46ee4 2400
c37e7851 2401 tm_format_datetime(tm, &config->tf_route, e->lastmod);
730f2e2c
MM
2402 if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw))
2403 bsprintf(from, " from %I", a->from);
2404 else
2405 from[0] = 0;
094d2bdb
OZ
2406
2407 get_route_info = a->src->proto->proto->get_route_info;
2408 if (get_route_info || d->verbose)
ce1da96e
MM
2409 {
2410 /* Need to normalize the extended attributes */
2411 ea_list *t = tmpa;
2412 t = ea_append(t, a->eattrs);
2413 tmpa = alloca(ea_scan(t));
2414 ea_merge(t, tmpa);
2f711231 2415 ea_sort(tmpa);
ce1da96e 2416 }
094d2bdb
OZ
2417 if (get_route_info)
2418 get_route_info(e, info, tmpa);
730f2e2c
MM
2419 else
2420 bsprintf(info, " (%d)", e->pref);
6887f409 2421 cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rt_format_via(e), a->src->proto->name,
32f95476 2422 tm, from, primary ? (sync_error ? " !" : " *") : "", info);
7e95c05d
OZ
2423 for (nh = a->nexthops; nh; nh = nh->next)
2424 cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1);
730f2e2c 2425 if (d->verbose)
ce1da96e 2426 rta_show(c, a, tmpa);
730f2e2c
MM
2427}
2428
2429static void
2430rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
2431{
2432 rte *e, *ee;
2433 byte ia[STD_ADDRESS_P_LENGTH+8];
c865cae3
OZ
2434 struct ea_list *tmpa;
2435 struct announce_hook *a = NULL;
2436 int first = 1;
2437 int pass = 0;
730f2e2c
MM
2438
2439 bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen);
cf98be7b 2440
c865cae3
OZ
2441 if (d->export_mode)
2442 {
7aa80901
OZ
2443 if (! d->export_protocol->rt_notify)
2444 return;
2445
c865cae3
OZ
2446 a = proto_find_announce_hook(d->export_protocol, d->table);
2447 if (!a)
2448 return;
2449 }
2450
2451 for (e = n->routes; e; e = e->next)
730f2e2c 2452 {
15550957 2453 if (rte_is_filtered(e) != d->filtered)
cf98be7b
OZ
2454 continue;
2455
23693958 2456 d->rt_counter++;
c865cae3
OZ
2457 d->net_counter += first;
2458 first = 0;
2459
2460 if (pass)
2461 continue;
2462
730f2e2c
MM
2463 ee = e;
2464 rte_update_lock(); /* We use the update buffer for filtering */
f2dd602f 2465 tmpa = rte_make_tmp_attrs(e, rte_update_pool);
c865cae3 2466
8d9eef17
OZ
2467 /* Special case for merged export */
2468 if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED))
2469 {
2470 rte *rt_free;
a290da25 2471 e = rt_export_merged(a, n, &rt_free, &tmpa, rte_update_pool, 1);
8d9eef17
OZ
2472 pass = 1;
2473
2474 if (!e)
2475 { e = ee; goto skip; }
2476 }
2477 else if (d->export_mode)
ce1da96e 2478 {
c865cae3
OZ
2479 struct proto *ep = d->export_protocol;
2480 int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0;
2481
8d9eef17 2482 if (ep->accept_ra_types == RA_OPTIMAL || ep->accept_ra_types == RA_MERGED)
c865cae3
OZ
2483 pass = 1;
2484
2485 if (ic < 0)
2486 goto skip;
2487
7aa80901 2488 if (d->export_mode > RSEM_PREEXPORT)
ce1da96e 2489 {
c865cae3
OZ
2490 /*
2491 * FIXME - This shows what should be exported according to current
2492 * filters, but not what was really exported. 'configure soft'
2493 * command may change the export filter and do not update routes.
2494 */
7aa80901
OZ
2495 int do_export = (ic > 0) ||
2496 (f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
c865cae3 2497
7aa80901 2498 if (do_export != (d->export_mode == RSEM_EXPORT))
c865cae3
OZ
2499 goto skip;
2500
7aa80901 2501 if ((d->export_mode == RSEM_EXPORT) && (ep->accept_ra_types == RA_ACCEPTED))
c865cae3 2502 pass = 1;
ce1da96e
MM
2503 }
2504 }
c865cae3
OZ
2505
2506 if (d->show_protocol && (d->show_protocol != e->attrs->src->proto))
2507 goto skip;
2508
2509 if (f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
2510 goto skip;
2511
2512 d->show_counter++;
2513 if (d->stats < 2)
2514 rt_show_rte(c, ia, e, d, tmpa);
2515 ia[0] = 0;
2516
2517 skip:
730f2e2c 2518 if (e != ee)
5e9bdac2
OZ
2519 {
2520 rte_free(e);
2521 e = ee;
2522 }
730f2e2c 2523 rte_update_unlock();
c865cae3 2524
0117d004 2525 if (d->primary_only)
ce1da96e 2526 break;
730f2e2c
MM
2527 }
2528}
2529
2530static void
2531rt_show_cont(struct cli *c)
2532{
2533 struct rt_show_data *d = c->rover;
f098e072
MM
2534#ifdef DEBUGGING
2535 unsigned max = 4;
2536#else
2537 unsigned max = 64;
2538#endif
730f2e2c
MM
2539 struct fib *fib = &d->table->fib;
2540 struct fib_iterator *it = &d->fit;
2541
2542 FIB_ITERATE_START(fib, it, f)
2543 {
2544 net *n = (net *) f;
ce1da96e
MM
2545 if (d->running_on_config && d->running_on_config != config)
2546 {
2547 cli_printf(c, 8004, "Stopped due to reconfiguration");
2548 goto done;
2549 }
0c791f87 2550 if (d->export_protocol && (d->export_protocol->export_state == ES_DOWN))
ce1da96e
MM
2551 {
2552 cli_printf(c, 8005, "Protocol is down");
2553 goto done;
2554 }
730f2e2c
MM
2555 if (!max--)
2556 {
2557 FIB_ITERATE_PUT(it, f);
2558 return;
2559 }
2560 rt_show_net(c, n, d);
2561 }
2562 FIB_ITERATE_END(f);
23693958
MM
2563 if (d->stats)
2564 cli_printf(c, 14, "%d of %d routes for %d networks", d->show_counter, d->rt_counter, d->net_counter);
2565 else
2566 cli_printf(c, 0, "");
ce1da96e 2567done:
730f2e2c
MM
2568 c->cont = c->cleanup = NULL;
2569}
2570
2571static void
2572rt_show_cleanup(struct cli *c)
2573{
2574 struct rt_show_data *d = c->rover;
2575
2576 /* Unlink the iterator */
2577 fit_get(&d->table->fib, &d->fit);
2578}
2579
2580void
2581rt_show(struct rt_show_data *d)
2582{
730f2e2c
MM
2583 net *n;
2584
e667622a 2585 /* Default is either a master table or a table related to a respective protocol */
c865cae3
OZ
2586 if (!d->table && d->export_protocol) d->table = d->export_protocol->table;
2587 if (!d->table && d->show_protocol) d->table = d->show_protocol->table;
e667622a
OF
2588 if (!d->table) d->table = config->master_rtc->table;
2589
c865cae3
OZ
2590 /* Filtered routes are neither exported nor have sensible ordering */
2591 if (d->filtered && (d->export_mode || d->primary_only))
2592 cli_msg(0, "");
2593
730f2e2c
MM
2594 if (d->pxlen == 256)
2595 {
2596 FIB_ITERATE_INIT(&d->fit, &d->table->fib);
2597 this_cli->cont = rt_show_cont;
2598 this_cli->cleanup = rt_show_cleanup;
2599 this_cli->rover = d;
2600 }
2601 else
2602 {
9449c91a 2603 if (d->show_for)
d1e146f2 2604 n = net_route(d->table, d->prefix, d->pxlen);
9449c91a 2605 else
d1e146f2 2606 n = net_find(d->table, d->prefix, d->pxlen);
0da562a7 2607
730f2e2c 2608 if (n)
0da562a7
OZ
2609 rt_show_net(this_cli, n, d);
2610
2611 if (d->rt_counter)
2612 cli_msg(0, "");
730f2e2c
MM
2613 else
2614 cli_msg(8001, "Network not in table");
2615 }
2616}
3ce8c610
MM
2617
2618/*
2619 * Documentation for functions declared inline in route.h
2620 */
2621#if 0
2622
2623/**
2624 * net_find - find a network entry
2625 * @tab: a routing table
2626 * @addr: address of the network
2627 * @len: length of the network prefix
2628 *
2629 * net_find() looks up the given network in routing table @tab and
2630 * returns a pointer to its &net entry or %NULL if no such network
2631 * exists.
2632 */
2633static inline net *net_find(rtable *tab, ip_addr addr, unsigned len)
2634{ DUMMY; }
2635
2636/**
2637 * net_get - obtain a network entry
2638 * @tab: a routing table
2639 * @addr: address of the network
2640 * @len: length of the network prefix
2641 *
2642 * net_get() looks up the given network in routing table @tab and
2643 * returns a pointer to its &net entry. If no such entry exists, it's
2644 * created.
2645 */
2646static inline net *net_get(rtable *tab, ip_addr addr, unsigned len)
2647{ DUMMY; }
2648
2649/**
2650 * rte_cow - copy a route for writing
2651 * @r: a route entry to be copied
2652 *
2653 * rte_cow() takes a &rte and prepares it for modification. The exact action
2654 * taken depends on the flags of the &rte -- if it's a temporary entry, it's
2655 * just returned unchanged, else a new temporary entry with the same contents
2656 * is created.
2657 *
2658 * The primary use of this function is inside the filter machinery -- when
2659 * a filter wants to modify &rte contents (to change the preference or to
2660 * attach another set of attributes), it must ensure that the &rte is not
2661 * shared with anyone else (and especially that it isn't stored in any routing
2662 * table).
2663 *
2e9b2421 2664 * Result: a pointer to the new writable &rte.
3ce8c610
MM
2665 */
2666static inline rte * rte_cow(rte *r)
2667{ DUMMY; }
2668
2669#endif