]> git.ipfire.org Git - thirdparty/bird.git/blame - nest/rt-table.c
Conf: Fixes bug in symbol lookup during reconfiguration
[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
cfd46ee4 53static void rt_format_via(rte *e, byte *via);
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
094d2bdb
OZ
63static inline struct ea_list *
64make_tmp_attrs(struct rte *rt, struct linpool *pool)
65{
66 struct ea_list *(*mta)(struct rte *rt, struct linpool *pool);
67 mta = rt->attrs->src->proto->make_tmp_attrs;
68 return mta ? mta(rt, rte_update_pool) : NULL;
69}
70
d1e146f2
OZ
71/* Like fib_route(), but skips empty net entries */
72static net *
73net_route(rtable *tab, ip_addr a, int len)
74{
75 ip_addr a0;
76 net *n;
77
78 while (len >= 0)
79 {
80 a0 = ipa_and(a, ipa_mkmask(len));
81 n = fib_find(&tab->fib, &a0, len);
cf98be7b 82 if (n && rte_is_valid(n->routes))
d1e146f2
OZ
83 return n;
84 len--;
85 }
86 return NULL;
87}
88
5996da6a 89static void
2326b001
MM
90rte_init(struct fib_node *N)
91{
92 net *n = (net *) N;
93
4c45595e 94 N->flags = 0;
2326b001
MM
95 n->routes = NULL;
96}
97
58740ed4
MM
98/**
99 * rte_find - find a route
100 * @net: network node
094d2bdb 101 * @src: route source
58740ed4
MM
102 *
103 * The rte_find() function returns a route for destination @net
094d2bdb 104 * which is from route source @src.
58740ed4 105 */
2326b001 106rte *
094d2bdb 107rte_find(net *net, struct rte_src *src)
2326b001
MM
108{
109 rte *e = net->routes;
110
094d2bdb 111 while (e && e->attrs->src != src)
2326b001
MM
112 e = e->next;
113 return e;
114}
115
58740ed4
MM
116/**
117 * rte_get_temp - get a temporary &rte
3ce8c610 118 * @a: attributes to assign to the new route (a &rta; in case it's
2e9b2421 119 * un-cached, rte_update() will create a cached copy automatically)
58740ed4
MM
120 *
121 * Create a temporary &rte and bind it with the attributes @a.
122 * Also set route preference to the default preference set for
123 * the protocol.
124 */
2326b001
MM
125rte *
126rte_get_temp(rta *a)
127{
128 rte *e = sl_alloc(rte_slab);
129
130 e->attrs = a;
0cdbd397 131 e->flags = 0;
094d2bdb 132 e->pref = a->src->proto->preference;
2326b001
MM
133 return e;
134}
135
e2dc2f30
MM
136rte *
137rte_do_cow(rte *r)
138{
139 rte *e = sl_alloc(rte_slab);
140
141 memcpy(e, r, sizeof(rte));
142 e->attrs = rta_clone(r->attrs);
143 e->flags = 0;
144 return e;
145}
146
8d9eef17
OZ
147/**
148 * rte_cow_rta - get a private writable copy of &rte with writable &rta
149 * @r: a route entry to be copied
150 * @lp: a linpool from which to allocate &rta
151 *
152 * rte_cow_rta() takes a &rte and prepares it and associated &rta for
153 * modification. There are three possibilities: First, both &rte and &rta are
154 * private copies, in that case they are returned unchanged. Second, &rte is
155 * private copy, but &rta is cached, in that case &rta is duplicated using
156 * rta_do_cow(). Third, both &rte is shared and &rta is cached, in that case
157 * both structures are duplicated by rte_do_cow() and rta_do_cow().
158 *
159 * Note that in the second case, cached &rta loses one reference, while private
160 * copy created by rta_do_cow() is a shallow copy sharing indirect data (eattrs,
161 * nexthops, ...) with it. To work properly, original shared &rta should have
162 * another reference during the life of created private copy.
163 *
164 * Result: a pointer to the new writable &rte with writable &rta.
165 */
166rte *
167rte_cow_rta(rte *r, linpool *lp)
168{
169 if (!rta_is_cached(r->attrs))
170 return r;
171
172 rte *e = rte_cow(r);
173 rta *a = rta_do_cow(r->attrs, lp);
174 rta_free(e->attrs);
175 e->attrs = a;
176 return e;
177}
178
2326b001
MM
179static int /* Actually better or at least as good as */
180rte_better(rte *new, rte *old)
181{
d9f330c5
MM
182 int (*better)(rte *, rte *);
183
cf98be7b 184 if (!rte_is_valid(old))
2326b001 185 return 1;
cf98be7b
OZ
186 if (!rte_is_valid(new))
187 return 0;
188
2326b001
MM
189 if (new->pref > old->pref)
190 return 1;
191 if (new->pref < old->pref)
192 return 0;
094d2bdb 193 if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
4c1b4e1a
MM
194 {
195 /*
196 * If the user has configured protocol preferences, so that two different protocols
197 * have the same preference, try to break the tie by comparing addresses. Not too
198 * useful, but keeps the ordering of routes unambiguous.
199 */
094d2bdb 200 return new->attrs->src->proto->proto > old->attrs->src->proto->proto;
4c1b4e1a 201 }
094d2bdb 202 if (better = new->attrs->src->proto->rte_better)
d9f330c5
MM
203 return better(new, old);
204 return 0;
2326b001
MM
205}
206
8d9eef17
OZ
207static int
208rte_mergable(rte *pri, rte *sec)
209{
210 int (*mergable)(rte *, rte *);
211
212 if (!rte_is_valid(pri) || !rte_is_valid(sec))
213 return 0;
214
215 if (pri->pref != sec->pref)
216 return 0;
217
218 if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto)
219 return 0;
220
221 if (mergable = pri->attrs->src->proto->rte_mergable)
222 return mergable(pri, sec);
223
224 return 0;
225}
226
cfd46ee4
MM
227static void
228rte_trace(struct proto *p, rte *e, int dir, char *msg)
229{
230 byte via[STD_ADDRESS_P_LENGTH+32];
231
232 rt_format_via(e, via);
233 log(L_TRACE "%s %c %s %I/%d %s", p->name, dir, msg, e->net->n.prefix, e->net->n.pxlen, via);
234}
235
236static inline void
ae80a2de 237rte_trace_in(uint flag, struct proto *p, rte *e, char *msg)
cfd46ee4
MM
238{
239 if (p->debug & flag)
b0a47440 240 rte_trace(p, e, '>', msg);
cfd46ee4
MM
241}
242
243static inline void
ae80a2de 244rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
cfd46ee4
MM
245{
246 if (p->debug & flag)
b0a47440 247 rte_trace(p, e, '<', msg);
cfd46ee4
MM
248}
249
00a09f3c
OZ
250static rte *
251export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
529c4149 252{
c0adf7e9
OZ
253 struct proto *p = ah->proto;
254 struct filter *filter = ah->out_filter;
255 struct proto_stats *stats = ah->stats;
00a09f3c
OZ
256 ea_list *tmpb = NULL;
257 rte *rt;
258 int v;
c0adf7e9 259
00a09f3c
OZ
260 rt = rt0;
261 *rt_free = NULL;
7de45ba4 262
00a09f3c 263 if (!tmpa)
db027a41
OZ
264 tmpa = &tmpb;
265
266 *tmpa = make_tmp_attrs(rt, rte_update_pool);
925fe2d3 267
00a09f3c
OZ
268 v = p->import_control ? p->import_control(p, &rt, tmpa, rte_update_pool) : 0;
269 if (v < 0)
270 {
271 if (silent)
272 goto reject;
11361a10 273
00a09f3c 274 stats->exp_updates_rejected++;
36da2857
OZ
275 if (v == RIC_REJECT)
276 rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
00a09f3c
OZ
277 goto reject;
278 }
279 if (v > 0)
e2dc2f30 280 {
00a09f3c
OZ
281 if (!silent)
282 rte_trace_out(D_FILTERS, p, rt, "forced accept by protocol");
283 goto accept;
e2dc2f30 284 }
925fe2d3 285
00a09f3c
OZ
286 v = filter && ((filter == FILTER_REJECT) ||
287 (f_run(filter, &rt, tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT));
288 if (v)
289 {
290 if (silent)
291 goto reject;
292
293 stats->exp_updates_filtered++;
294 rte_trace_out(D_FILTERS, p, rt, "filtered out");
295 goto reject;
e2dc2f30 296 }
925fe2d3 297
00a09f3c
OZ
298 accept:
299 if (rt != rt0)
300 *rt_free = rt;
301 return rt;
302
303 reject:
304 /* Discard temporary rte */
305 if (rt != rt0)
306 rte_free(rt);
307 return NULL;
308}
309
310static void
311do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
312{
313 struct proto *p = ah->proto;
314 struct proto_stats *stats = ah->stats;
925fe2d3 315
abced4a9 316
ab758e4f 317 /*
abced4a9
OZ
318 * First, apply export limit.
319 *
ab758e4f
OZ
320 * Export route limits has several problems. Because exp_routes
321 * counter is reset before refeed, we don't really know whether
abced4a9 322 * limit is breached and whether the update is new or not. Therefore
ab758e4f
OZ
323 * the number of really exported routes may exceed the limit
324 * temporarily (routes exported before and new routes in refeed).
325 *
326 * Minor advantage is that if the limit is decreased and refeed is
327 * requested, the number of exported routes really decrease.
328 *
329 * Second problem is that with export limits, we don't know whether
330 * old was really exported (it might be blocked by limit). When a
331 * withdraw is exported, we announce it even when the previous
332 * update was blocked. This is not a big issue, but the same problem
333 * is in updating exp_routes counter. Therefore, to be consistent in
334 * increases and decreases of exp_routes, we count exported routes
335 * regardless of blocking by limits.
336 *
337 * Similar problem is in handling updates - when a new route is
338 * received and blocking is active, the route would be blocked, but
339 * when an update for the route will be received later, the update
340 * would be propagated (as old != NULL). Therefore, we have to block
341 * also non-new updates (contrary to import blocking).
342 */
925fe2d3 343
d9b77cc2 344 struct proto_limit *l = ah->out_limit;
ab758e4f 345 if (l && new)
d9b77cc2 346 {
ab758e4f 347 if ((!old || refeed) && (stats->exp_routes >= l->limit))
b662290f 348 proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
d9b77cc2
OZ
349
350 if (l->state == PLS_BLOCKED)
351 {
ab758e4f 352 stats->exp_routes++; /* see note above */
d9b77cc2
OZ
353 stats->exp_updates_rejected++;
354 rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
ab758e4f 355 new = NULL;
abced4a9
OZ
356
357 if (!old)
358 return;
d9b77cc2
OZ
359 }
360 }
361
ab758e4f 362
925fe2d3 363 if (new)
9db74169 364 stats->exp_updates_accepted++;
925fe2d3 365 else
9db74169 366 stats->exp_withdraws_accepted++;
925fe2d3 367
8a7fb885
OZ
368 /* Hack: We do not decrease exp_routes during refeed, we instead
369 reset exp_routes at the start of refeed. */
925fe2d3 370 if (new)
9db74169 371 stats->exp_routes++;
8a7fb885 372 if (old && !refeed)
9db74169 373 stats->exp_routes--;
925fe2d3 374
cfd46ee4
MM
375 if (p->debug & D_ROUTES)
376 {
377 if (new && old)
378 rte_trace_out(D_ROUTES, p, new, "replaced");
379 else if (new)
380 rte_trace_out(D_ROUTES, p, new, "added");
349e21bb 381 else if (old)
cfd46ee4
MM
382 rte_trace_out(D_ROUTES, p, old, "removed");
383 }
08f0290a 384 if (!new)
c0adf7e9 385 p->rt_notify(p, ah->table, net, NULL, old, NULL);
08f0290a
MM
386 else if (tmpa)
387 {
2f711231
MM
388 ea_list *t = tmpa;
389 while (t->next)
390 t = t->next;
391 t->next = new->attrs->eattrs;
c0adf7e9 392 p->rt_notify(p, ah->table, net, new, old, tmpa);
2f711231 393 t->next = NULL;
08f0290a
MM
394 }
395 else
c0adf7e9 396 p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
00a09f3c
OZ
397}
398
00a09f3c 399static void
db027a41 400rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int refeed)
00a09f3c 401{
86f567e1 402 struct proto *p = ah->proto;
00a09f3c
OZ
403 struct proto_stats *stats = ah->stats;
404
86f567e1
OZ
405 rte *new = new0;
406 rte *old = old0;
00a09f3c
OZ
407 rte *new_free = NULL;
408 rte *old_free = NULL;
db027a41 409 ea_list *tmpa = NULL;
00a09f3c
OZ
410
411 if (new)
412 stats->exp_updates_received++;
413 else
414 stats->exp_withdraws_received++;
415
416 /*
417 * This is a tricky part - we don't know whether route 'old' was
418 * exported to protocol 'p' or was filtered by the export filter.
419 * We try to run the export filter to know this to have a correct
420 * value in 'old' argument of rte_update (and proper filter value)
421 *
422 * FIXME - this is broken because 'configure soft' may change
423 * filters but keep routes. Refeed is expected to be called after
424 * change of the filters and with old == new, therefore we do not
86f567e1 425 * even try to run the filter on an old route, This may lead to
00a09f3c
OZ
426 * 'spurious withdraws' but ensure that there are no 'missing
427 * withdraws'.
428 *
429 * This is not completely safe as there is a window between
430 * reconfiguration and the end of refeed - if a newly filtered
431 * route disappears during this period, proper withdraw is not
432 * sent (because old would be also filtered) and the route is
433 * not refeeded (because it disappeared before that).
434 */
435
436 if (new)
437 new = export_filter(ah, new, &new_free, &tmpa, 0);
438
439 if (old && !refeed)
440 old = export_filter(ah, old, &old_free, NULL, 1);
441
00a09f3c 442 if (!new && !old)
86f567e1
OZ
443 {
444 /*
445 * As mentioned above, 'old' value may be incorrect in some race conditions.
446 * We generally ignore it with the exception of withdraw to pipe protocol.
447 * In that case we rather propagate unfiltered withdraws regardless of
448 * export filters to ensure that when a protocol is flushed, its routes are
449 * removed from all tables. Possible spurious unfiltered withdraws are not
450 * problem here as they are ignored if there is no corresponding route at
451 * the other end of the pipe. We directly call rt_notify() hook instead of
452 * do_rt_notify() to avoid logging and stat counters.
453 */
454
455#ifdef CONFIG_PIPE
456 if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto))
457 p->rt_notify(p, ah->table, net, NULL, old0, NULL);
458#endif
459
00a09f3c 460 return;
86f567e1 461 }
00a09f3c
OZ
462
463 do_rt_notify(ah, net, new, old, tmpa, refeed);
464
465 /* Discard temporary rte's */
466 if (new_free)
467 rte_free(new_free);
468 if (old_free)
469 rte_free(old_free);
470}
471
472static void
db027a41 473rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
00a09f3c
OZ
474{
475 // struct proto *p = ah->proto;
476 struct proto_stats *stats = ah->stats;
477
db027a41 478 rte *r;
00a09f3c
OZ
479 rte *new_best = NULL;
480 rte *old_best = NULL;
481 rte *new_free = NULL;
482 rte *old_free = NULL;
db027a41 483 ea_list *tmpa = NULL;
00a09f3c 484
cf98be7b
OZ
485 /* Used to track whether we met old_changed position. If before_old is NULL
486 old_changed was the first and we met it implicitly before current best route. */
487 int old_meet = old_changed && !before_old;
488
489 /* Note that before_old is either NULL or valid (not rejected) route.
490 If old_changed is valid, before_old have to be too. If old changed route
491 was not valid, caller must use NULL for both old_changed and before_old. */
00a09f3c
OZ
492
493 if (new_changed)
494 stats->exp_updates_received++;
495 else
496 stats->exp_withdraws_received++;
497
498 /* First, find the new_best route - first accepted by filters */
cf98be7b 499 for (r=net->routes; rte_is_valid(r); r=r->next)
00a09f3c
OZ
500 {
501 if (new_best = export_filter(ah, r, &new_free, &tmpa, 0))
502 break;
503
504 /* Note if we walked around the position of old_changed route */
505 if (r == before_old)
506 old_meet = 1;
507 }
508
509 /*
510 * Second, handle the feed case. That means we do not care for
511 * old_best. It is NULL for feed, and the new_best for refeed.
512 * For refeed, there is a hack similar to one in rt_notify_basic()
513 * to ensure withdraws in case of changed filters
514 */
515 if (feed)
516 {
517 if (feed == 2) /* refeed */
cf98be7b
OZ
518 old_best = new_best ? new_best :
519 (rte_is_valid(net->routes) ? net->routes : NULL);
00a09f3c
OZ
520 else
521 old_best = NULL;
522
523 if (!new_best && !old_best)
524 return;
525
526 goto found;
527 }
528
529 /*
530 * Now, we find the old_best route. Generally, it is the same as the
531 * new_best, unless new_best is the same as new_changed or
532 * old_changed is accepted before new_best.
533 *
534 * There are four cases:
535 *
536 * - We would find and accept old_changed before new_best, therefore
537 * old_changed is old_best. In remaining cases we suppose this
538 * is not true.
539 *
540 * - We found no new_best, therefore there is also no old_best and
541 * we ignore this withdraw.
542 *
543 * - We found new_best different than new_changed, therefore
544 * old_best is the same as new_best and we ignore this update.
545 *
546 * - We found new_best the same as new_changed, therefore it cannot
547 * be old_best and we have to continue search for old_best.
548 */
549
550 /* First case */
551 if (old_meet)
552 if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
553 goto found;
554
555 /* Second case */
556 if (!new_best)
557 return;
d9b77cc2 558
26822d8f 559 /* Third case, we use r instead of new_best, because export_filter() could change it */
00a09f3c
OZ
560 if (r != new_changed)
561 {
562 if (new_free)
563 rte_free(new_free);
564 return;
565 }
566
567 /* Fourth case */
cf98be7b 568 for (r=r->next; rte_is_valid(r); r=r->next)
00a09f3c
OZ
569 {
570 if (old_best = export_filter(ah, r, &old_free, NULL, 1))
571 goto found;
572
573 if (r == before_old)
574 if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
575 goto found;
576 }
577
578 /* Implicitly, old_best is NULL and new_best is non-NULL */
579
580 found:
581 do_rt_notify(ah, net, new_best, old_best, tmpa, (feed == 2));
582
583 /* Discard temporary rte's */
584 if (new_free)
585 rte_free(new_free);
586 if (old_free)
587 rte_free(old_free);
529c4149
MM
588}
589
8d9eef17
OZ
590
591static struct mpnh *
592mpnh_merge_rta(struct mpnh *nhs, rta *a, int max)
593{
594 struct mpnh nh = { .gw = a->gw, .iface = a->iface };
595 struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh;
596 return mpnh_merge(nhs, nh2, 1, 0, max, rte_update_pool);
597}
598
599rte *
600rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, int silent)
601{
602 // struct proto *p = ah->proto;
603 struct mpnh *nhs = NULL;
604 rte *best0, *best, *rt0, *rt, *tmp;
605
606 best0 = net->routes;
607 *rt_free = NULL;
608
609 if (!rte_is_valid(best0))
610 return NULL;
611
612 best = export_filter(ah, best0, rt_free, tmpa, silent);
613
614 if (!best || !rte_is_reachable(best))
615 return best;
616
617 for (rt0 = best0->next; rt0; rt0 = rt0->next)
618 {
619 if (!rte_mergable(best0, rt0))
620 continue;
621
622 rt = export_filter(ah, rt0, &tmp, NULL, 1);
623
624 if (!rt)
625 continue;
626
627 if (rte_is_reachable(rt))
628 nhs = mpnh_merge_rta(nhs, rt->attrs, ah->proto->merge_limit);
629
630 if (tmp)
631 rte_free(tmp);
632 }
633
634 if (nhs)
635 {
636 nhs = mpnh_merge_rta(nhs, best->attrs, ah->proto->merge_limit);
637
638 if (nhs->next)
639 {
640 best = rte_cow_rta(best, rte_update_pool);
641 best->attrs->dest = RTD_MULTIPATH;
642 best->attrs->nexthops = nhs;
643 }
644 }
645
646 if (best != best0)
647 *rt_free = best;
648
649 return best;
650}
651
652
653static void
654rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed,
655 rte *new_best, rte*old_best, int refeed)
656{
657 // struct proto *p = ah->proto;
658
659 rte *new_best_free = NULL;
660 rte *old_best_free = NULL;
661 rte *new_changed_free = NULL;
662 rte *old_changed_free = NULL;
663 ea_list *tmpa = NULL;
664
665 /* We assume that all rte arguments are either NULL or rte_is_valid() */
666
667 /* This check should be done by the caller */
668 if (!new_best && !old_best)
669 return;
670
671 /* Check whether the change is relevant to the merged route */
672 if ((new_best == old_best) && !refeed)
673 {
674 new_changed = rte_mergable(new_best, new_changed) ?
675 export_filter(ah, new_changed, &new_changed_free, NULL, 1) : NULL;
676
677 old_changed = rte_mergable(old_best, old_changed) ?
678 export_filter(ah, old_changed, &old_changed_free, NULL, 1) : NULL;
679
680 if (!new_changed && !old_changed)
681 return;
682 }
683
684 if (new_best)
685 ah->stats->exp_updates_received++;
686 else
687 ah->stats->exp_withdraws_received++;
688
689 /* Prepare new merged route */
690 if (new_best)
691 new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, 0);
692
693 /* Prepare old merged route (without proper merged next hops) */
694 /* There are some issues with running filter on old route - see rt_notify_basic() */
695 if (old_best && !refeed)
696 old_best = export_filter(ah, old_best, &old_best_free, NULL, 1);
697
698 if (new_best || old_best)
699 do_rt_notify(ah, net, new_best, old_best, tmpa, refeed);
700
701 /* Discard temporary rte's */
702 if (new_best_free)
703 rte_free(new_best_free);
704 if (old_best_free)
705 rte_free(old_best_free);
706 if (new_changed_free)
707 rte_free(new_changed_free);
708 if (old_changed_free)
709 rte_free(old_changed_free);
710}
711
712
9a8f20fc
MM
713/**
714 * rte_announce - announce a routing table change
715 * @tab: table the route has been added to
23ac9e9a 716 * @type: type of route announcement (RA_OPTIMAL or RA_ANY)
9a8f20fc
MM
717 * @net: network in question
718 * @new: the new route to be announced
23ac9e9a 719 * @old: the previous route for the same network
9a8f20fc
MM
720 *
721 * This function gets a routing table update and announces it
f98e2915
OZ
722 * to all protocols that acccepts given type of route announcement
723 * and are connected to the same table by their announcement hooks.
9a8f20fc 724 *
f98e2915
OZ
725 * Route announcement of type RA_OPTIMAL si generated when optimal
726 * route (in routing table @tab) changes. In that case @old stores the
727 * old optimal route.
23ac9e9a 728 *
f98e2915
OZ
729 * Route announcement of type RA_ANY si generated when any route (in
730 * routing table @tab) changes In that case @old stores the old route
731 * from the same protocol.
732 *
733 * For each appropriate protocol, we first call its import_control()
734 * hook which performs basic checks on the route (each protocol has a
735 * right to veto or force accept of the route before any filter is
736 * asked) and adds default values of attributes specific to the new
737 * protocol (metrics, tags etc.). Then it consults the protocol's
738 * export filter and if it accepts the route, the rt_notify() hook of
739 * the protocol gets called.
9a8f20fc 740 */
e2dc2f30 741static void
8d9eef17
OZ
742rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
743 rte *new_best, rte *old_best, rte *before_old)
2326b001 744{
8d9eef17
OZ
745 if (!rte_is_valid(new))
746 new = NULL;
747
cf98be7b
OZ
748 if (!rte_is_valid(old))
749 old = before_old = NULL;
750
8d9eef17
OZ
751 if (!rte_is_valid(new_best))
752 new_best = NULL;
753
754 if (!rte_is_valid(old_best))
755 old_best = NULL;
cf98be7b
OZ
756
757 if (!old && !new)
758 return;
2326b001 759
925fe2d3
OZ
760 if (type == RA_OPTIMAL)
761 {
762 if (new)
094d2bdb 763 new->attrs->src->proto->stats.pref_routes++;
925fe2d3 764 if (old)
094d2bdb 765 old->attrs->src->proto->stats.pref_routes--;
cfe34a31
OZ
766
767 if (tab->hostcache)
768 rt_notify_hostcache(tab, net);
925fe2d3
OZ
769 }
770
cf98be7b 771 struct announce_hook *a;
0e02abfd 772 WALK_LIST(a, tab->hooks)
0a2e9d9f 773 {
0c791f87 774 ASSERT(a->proto->export_state != ES_DOWN);
23ac9e9a 775 if (a->proto->accept_ra_types == type)
00a09f3c 776 if (type == RA_ACCEPTED)
db027a41 777 rt_notify_accepted(a, net, new, old, before_old, 0);
8d9eef17
OZ
778 else if (type == RA_MERGED)
779 rt_notify_merged(a, net, new, old, new_best, old_best, 0);
00a09f3c 780 else
db027a41 781 rt_notify_basic(a, net, new, old, 0);
0a2e9d9f 782 }
2326b001
MM
783}
784
421838ff
MM
785static inline int
786rte_validate(rte *e)
787{
788 int c;
789 net *n = e->net;
790
852b7062 791 if ((n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
cfd46ee4 792 {
ab164971 793 log(L_WARN "Ignoring bogus prefix %I/%d received via %s",
c0adf7e9 794 n->n.prefix, n->n.pxlen, e->sender->proto->name);
cfd46ee4
MM
795 return 0;
796 }
ff2857b0
OZ
797
798 c = ipa_classify_net(n->n.prefix);
799 if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
421838ff 800 {
ff2857b0 801 log(L_WARN "Ignoring bogus route %I/%d received via %s",
c0adf7e9 802 n->n.prefix, n->n.pxlen, e->sender->proto->name);
ff2857b0 803 return 0;
421838ff 804 }
ff2857b0 805
421838ff
MM
806 return 1;
807}
808
58740ed4
MM
809/**
810 * rte_free - delete a &rte
811 * @e: &rte to be deleted
812 *
813 * rte_free() deletes the given &rte from the routing table it's linked to.
814 */
04925e90 815void
2326b001 816rte_free(rte *e)
04925e90 817{
094d2bdb 818 if (rta_is_cached(e->attrs))
04925e90
MM
819 rta_free(e->attrs);
820 sl_free(rte_slab, e);
821}
822
823static inline void
824rte_free_quick(rte *e)
2326b001
MM
825{
826 rta_free(e->attrs);
827 sl_free(rte_slab, e);
828}
829
67be5b23
MM
830static int
831rte_same(rte *x, rte *y)
832{
833 return
834 x->attrs == y->attrs &&
835 x->flags == y->flags &&
836 x->pflags == y->pflags &&
837 x->pref == y->pref &&
094d2bdb 838 (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y));
67be5b23
MM
839}
840
70577529
OZ
841static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
842
e2dc2f30 843static void
db027a41 844rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
2326b001 845{
c0adf7e9
OZ
846 struct proto *p = ah->proto;
847 struct rtable *table = ah->table;
848 struct proto_stats *stats = ah->stats;
1123e707 849 static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
00a09f3c 850 rte *before_old = NULL;
2326b001
MM
851 rte *old_best = net->routes;
852 rte *old = NULL;
00a09f3c 853 rte **k;
2326b001
MM
854
855 k = &net->routes; /* Find and remove original route from the same protocol */
856 while (old = *k)
857 {
094d2bdb 858 if (old->attrs->src == src)
2326b001 859 {
11787b84
OZ
860 /* If there is the same route in the routing table but from
861 * a different sender, then there are two paths from the
862 * source protocol to this routing table through transparent
863 * pipes, which is not allowed.
864 *
865 * We log that and ignore the route. If it is withdraw, we
866 * ignore it completely (there might be 'spurious withdraws',
867 * see FIXME in do_rte_announce())
868 */
c0adf7e9 869 if (old->sender->proto != p)
11787b84
OZ
870 {
871 if (new)
872 {
548c329c 873 log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %I/%d to table %s",
11787b84
OZ
874 net->n.prefix, net->n.pxlen, table->name);
875 rte_free_quick(new);
876 }
877 return;
878 }
879
0b761098 880 if (new && rte_same(old, new))
67be5b23
MM
881 {
882 /* No changes, ignore the new route */
cf98be7b 883
15550957 884 if (!rte_is_filtered(new))
cf98be7b
OZ
885 {
886 stats->imp_updates_ignored++;
887 rte_trace_in(D_ROUTES, p, new, "ignored");
888 }
889
67be5b23 890 rte_free_quick(new);
4d9a0d1f
OZ
891#ifdef CONFIG_RIP
892 /* lastmod is used internally by RIP as the last time
893 when the route was received. */
094d2bdb 894 if (src->proto->proto == &proto_rip)
4d9a0d1f
OZ
895 old->lastmod = now;
896#endif
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 {
736e143f 1218 tmpa = 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
5b22683d 1277void
0e02abfd 1278rte_discard(rtable *t, 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() */
736e143f 1298 ea_list *tmpa = 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
0e02abfd 1601 rte_discard(tab, 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
1625 *
1626 * This function scans the routing table @tab and removes routes belonging to
1627 * flushing protocols, discarded routes and also stale network entries, in a
1628 * similar fashion like rt_prune_loop(). Returns 1 when all such routes are
1629 * pruned. Contrary to rt_prune_loop(), this function is not a part of the
1630 * protocol flushing loop, but it is called from rt_event() for just one routing
1631 * table.
1632 *
1633 * Note that rt_prune_table() and rt_prune_loop() share (for each table) the
1634 * prune state (@prune_state) and also the pruning iterator (@prune_fit).
1635 */
0c791f87
OZ
1636static inline int
1637rt_prune_table(rtable *tab)
1638{
1639 int limit = 512;
d0e23d42 1640 return rt_prune_step(tab, &limit);
0c791f87
OZ
1641}
1642
58740ed4 1643/**
fb829de6 1644 * rt_prune_loop - prune routing tables
58740ed4 1645 *
6eda3f13
OZ
1646 * The prune loop scans routing tables and removes routes belonging to flushing
1647 * protocols, discarded routes and also stale network entries. Returns 1 when
1648 * all such routes are pruned. It is a part of the protocol flushing loop.
58740ed4 1649 */
fb829de6
OZ
1650int
1651rt_prune_loop(void)
0e02abfd 1652{
0c791f87 1653 int limit = 512;
9135c1f0 1654 rtable *t;
0e02abfd
MM
1655
1656 WALK_LIST(t, routing_tables)
d0e23d42 1657 if (! rt_prune_step(t, &limit))
fb829de6
OZ
1658 return 0;
1659
1660 return 1;
0e02abfd
MM
1661}
1662
cfe34a31
OZ
1663void
1664rt_preconfig(struct config *c)
1665{
9b9a7143 1666 struct symbol *s = cf_get_symbol("master");
cfe34a31
OZ
1667
1668 init_list(&c->tables);
1669 c->master_rtc = rt_new_table(s);
1670}
1671
1672
1673/*
1674 * Some functions for handing internal next hop updates
1675 * triggered by rt_schedule_nhu().
1676 */
1677
cfe34a31
OZ
1678static inline int
1679rta_next_hop_outdated(rta *a)
1680{
1681 struct hostentry *he = a->hostentry;
7e95c05d
OZ
1682
1683 if (!he)
1684 return 0;
1685
1686 if (!he->src)
1687 return a->dest != RTD_UNREACHABLE;
1688
1689 return (a->iface != he->src->iface) || !ipa_equal(a->gw, he->gw) ||
1690 (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
1691 !mpnh_same(a->nexthops, he->src->nexthops);
cfe34a31
OZ
1692}
1693
1694static inline void
1695rta_apply_hostentry(rta *a, struct hostentry *he)
1696{
1697 a->hostentry = he;
7e95c05d 1698 a->iface = he->src ? he->src->iface : NULL;
cfe34a31
OZ
1699 a->gw = he->gw;
1700 a->dest = he->dest;
d1e146f2 1701 a->igp_metric = he->igp_metric;
7e95c05d 1702 a->nexthops = he->src ? he->src->nexthops : NULL;
cfe34a31
OZ
1703}
1704
1705static inline rte *
1706rt_next_hop_update_rte(rtable *tab, rte *old)
1707{
1708 rta a;
1709 memcpy(&a, old->attrs, sizeof(rta));
1710 rta_apply_hostentry(&a, old->attrs->hostentry);
1711 a.aflags = 0;
1712
1713 rte *e = sl_alloc(rte_slab);
1714 memcpy(e, old, sizeof(rte));
1715 e->attrs = rta_lookup(&a);
1716
1717 return e;
1718}
1719
1720static inline int
1721rt_next_hop_update_net(rtable *tab, net *n)
1722{
1723 rte **k, *e, *new, *old_best, **new_best;
1724 int count = 0;
1725 int free_old_best = 0;
1726
1727 old_best = n->routes;
1728 if (!old_best)
1729 return 0;
1730
cfe34a31 1731 for (k = &n->routes; e = *k; k = &e->next)
be4cd99a
OZ
1732 if (rta_next_hop_outdated(e->attrs))
1733 {
1734 new = rt_next_hop_update_rte(tab, e);
1735 *k = new;
cfe34a31 1736
8d9eef17 1737 rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
c0adf7e9 1738 rte_trace_in(D_ROUTES, new->sender->proto, new, "updated");
cfe34a31 1739
be4cd99a
OZ
1740 /* Call a pre-comparison hook */
1741 /* Not really an efficient way to compute this */
094d2bdb
OZ
1742 if (e->attrs->src->proto->rte_recalculate)
1743 e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL);
cfe34a31 1744
be4cd99a
OZ
1745 if (e != old_best)
1746 rte_free_quick(e);
1747 else /* Freeing of the old best rte is postponed */
1748 free_old_best = 1;
cfe34a31 1749
be4cd99a
OZ
1750 e = new;
1751 count++;
1752 }
1753
1754 if (!count)
1755 return 0;
1756
1757 /* Find the new best route */
1758 new_best = NULL;
1759 for (k = &n->routes; e = *k; k = &e->next)
1760 {
cfe34a31
OZ
1761 if (!new_best || rte_better(e, *new_best))
1762 new_best = k;
1763 }
1764
1765 /* Relink the new best route to the first position */
1766 new = *new_best;
1767 if (new != n->routes)
1768 {
1769 *new_best = new->next;
1770 new->next = n->routes;
1771 n->routes = new;
1772 }
1773
1774 /* Announce the new best route */
1775 if (new != old_best)
1776 {
8d9eef17 1777 rte_announce_i(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL);
c0adf7e9 1778 rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]");
cfe34a31
OZ
1779 }
1780
8d9eef17
OZ
1781 /* FIXME: Better announcement of merged routes */
1782 rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best);
1783
cfe34a31
OZ
1784 if (free_old_best)
1785 rte_free_quick(old_best);
1786
1787 return count;
1788}
1789
1790static void
1791rt_next_hop_update(rtable *tab)
1792{
1793 struct fib_iterator *fit = &tab->nhu_fit;
1794 int max_feed = 32;
1795
1796 if (tab->nhu_state == 0)
1797 return;
1798
1799 if (tab->nhu_state == 1)
1800 {
1801 FIB_ITERATE_INIT(fit, &tab->fib);
1802 tab->nhu_state = 2;
1803 }
1804
1805 FIB_ITERATE_START(&tab->fib, fit, fn)
1806 {
1807 if (max_feed <= 0)
1808 {
1809 FIB_ITERATE_PUT(fit, fn);
1810 ev_schedule(tab->rt_event);
1811 return;
1812 }
1813 max_feed -= rt_next_hop_update_net(tab, (net *) fn);
1814 }
1815 FIB_ITERATE_END(fn);
1816
1817 /* state change 2->0, 3->1 */
1818 tab->nhu_state &= 1;
1819
1820 if (tab->nhu_state > 0)
1821 ev_schedule(tab->rt_event);
1822}
1823
1824
b9626ec6
MM
1825struct rtable_config *
1826rt_new_table(struct symbol *s)
1827{
36415e4b
OZ
1828 /* Hack that allows to 'redefine' the master table */
1829 if ((s->class == SYM_TABLE) && (s->def == new_config->master_rtc))
1830 return s->def;
1831
b9626ec6
MM
1832 struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
1833
1834 cf_define_symbol(s, SYM_TABLE, c);
1835 c->name = s->name;
1836 add_tail(&new_config->tables, &c->n);
2eca3b3a 1837 c->gc_max_ops = 1000;
b9626ec6
MM
1838 c->gc_min_time = 5;
1839 return c;
1840}
1841
58740ed4
MM
1842/**
1843 * rt_lock_table - lock a routing table
1844 * @r: routing table to be locked
1845 *
1846 * Lock a routing table, because it's in use by a protocol,
1847 * preventing it from being freed when it gets undefined in a new
1848 * configuration.
1849 */
0e02abfd 1850void
50fe90ed 1851rt_lock_table(rtable *r)
0e02abfd 1852{
50fe90ed
MM
1853 r->use_count++;
1854}
1855
58740ed4
MM
1856/**
1857 * rt_unlock_table - unlock a routing table
1858 * @r: routing table to be unlocked
1859 *
1860 * Unlock a routing table formerly locked by rt_lock_table(),
1861 * that is decrease its use count and delete it if it's scheduled
1862 * for deletion by configuration changes.
1863 */
50fe90ed
MM
1864void
1865rt_unlock_table(rtable *r)
1866{
1867 if (!--r->use_count && r->deleted)
1868 {
1869 struct config *conf = r->deleted;
1870 DBG("Deleting routing table %s\n", r->name);
cfe34a31
OZ
1871 if (r->hostcache)
1872 rt_free_hostcache(r);
50fe90ed
MM
1873 rem_node(&r->n);
1874 fib_free(&r->fib);
cfe34a31 1875 rfree(r->rt_event);
50fe90ed
MM
1876 mb_free(r);
1877 config_del_obstacle(conf);
1878 }
1879}
1880
58740ed4
MM
1881/**
1882 * rt_commit - commit new routing table configuration
1883 * @new: new configuration
1884 * @old: original configuration or %NULL if it's boot time config
1885 *
1886 * Scan differences between @old and @new configuration and modify
1887 * the routing tables according to these changes. If @new defines a
1888 * previously unknown table, create it, if it omits a table existing
1889 * in @old, schedule it for deletion (it gets deleted when all protocols
1890 * disconnect from it by calling rt_unlock_table()), if it exists
1891 * in both configurations, leave it unchanged.
1892 */
50fe90ed
MM
1893void
1894rt_commit(struct config *new, struct config *old)
1895{
1896 struct rtable_config *o, *r;
0e02abfd 1897
50fe90ed
MM
1898 DBG("rt_commit:\n");
1899 if (old)
0e02abfd 1900 {
50fe90ed
MM
1901 WALK_LIST(o, old->tables)
1902 {
1903 rtable *ot = o->table;
1904 if (!ot->deleted)
1905 {
9b9a7143 1906 struct symbol *sym = cf_find_symbol(new, o->name);
bf8558bc 1907 if (sym && sym->class == SYM_TABLE && !new->shutdown)
50fe90ed
MM
1908 {
1909 DBG("\t%s: same\n", o->name);
1910 r = sym->def;
1911 r->table = ot;
1912 ot->name = r->name;
b9626ec6 1913 ot->config = r;
26822d8f
OZ
1914 if (o->sorted != r->sorted)
1915 log(L_WARN "Reconfiguration of rtable sorted flag not implemented");
50fe90ed
MM
1916 }
1917 else
1918 {
bf8558bc 1919 DBG("\t%s: deleted\n", o->name);
50fe90ed
MM
1920 ot->deleted = old;
1921 config_add_obstacle(old);
1922 rt_lock_table(ot);
1923 rt_unlock_table(ot);
1924 }
1925 }
1926 }
0e02abfd 1927 }
50fe90ed
MM
1928
1929 WALK_LIST(r, new->tables)
1930 if (!r->table)
1931 {
1932 rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
1933 DBG("\t%s: created\n", r->name);
b9626ec6 1934 rt_setup(rt_table_pool, t, r->name, r);
50fe90ed
MM
1935 add_tail(&routing_tables, &t->n);
1936 r->table = t;
1937 }
1938 DBG("\tdone\n");
0e02abfd 1939}
730f2e2c 1940
23ac9e9a
OZ
1941static inline void
1942do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
1943{
23ac9e9a 1944 rte_update_lock();
00a09f3c 1945 if (type == RA_ACCEPTED)
db027a41 1946 rt_notify_accepted(h, n, e, NULL, NULL, p->refeeding ? 2 : 1);
8d9eef17
OZ
1947 else if (type == RA_MERGED)
1948 rt_notify_merged(h, n, NULL, NULL, e, p->refeeding ? e : NULL, p->refeeding);
00a09f3c 1949 else
db027a41 1950 rt_notify_basic(h, n, e, p->refeeding ? e : NULL, p->refeeding);
23ac9e9a
OZ
1951 rte_update_unlock();
1952}
1953
58740ed4
MM
1954/**
1955 * rt_feed_baby - advertise routes to a new protocol
1956 * @p: protocol to be fed
1957 *
1958 * This function performs one pass of advertisement of routes to a newly
1959 * initialized protocol. It's called by the protocol code as long as it
1960 * has something to do. (We avoid transferring all the routes in single
1961 * pass in order not to monopolize CPU time.)
1962 */
ac5d8012
MM
1963int
1964rt_feed_baby(struct proto *p)
1965{
1966 struct announce_hook *h;
1967 struct fib_iterator *fit;
76dfda9e 1968 int max_feed = 256;
ac5d8012
MM
1969
1970 if (!p->feed_ahook) /* Need to initialize first */
1971 {
1972 if (!p->ahooks)
1973 return 1;
1974 DBG("Announcing routes to new protocol %s\n", p->name);
1975 p->feed_ahook = p->ahooks;
1976 fit = p->feed_iterator = mb_alloc(p->pool, sizeof(struct fib_iterator));
1977 goto next_hook;
1978 }
1979 fit = p->feed_iterator;
1980
1981again:
1982 h = p->feed_ahook;
1983 FIB_ITERATE_START(&h->table->fib, fit, fn)
1984 {
1985 net *n = (net *) fn;
258d0ad4 1986 rte *e = n->routes;
76dfda9e
MM
1987 if (max_feed <= 0)
1988 {
1989 FIB_ITERATE_PUT(fit, fn);
1990 return 0;
1991 }
23ac9e9a 1992
cf98be7b
OZ
1993 /* XXXX perhaps we should change feed for RA_ACCEPTED to not use 'new' */
1994
b7f3df79 1995 if ((p->accept_ra_types == RA_OPTIMAL) ||
8d9eef17
OZ
1996 (p->accept_ra_types == RA_ACCEPTED) ||
1997 (p->accept_ra_types == RA_MERGED))
cf98be7b 1998 if (rte_is_valid(e))
23ac9e9a 1999 {
0c791f87 2000 if (p->export_state != ES_FEEDING)
23ac9e9a 2001 return 1; /* In the meantime, the protocol fell down. */
ca34698c 2002
b7f3df79 2003 do_feed_baby(p, p->accept_ra_types, h, n, e);
23ac9e9a
OZ
2004 max_feed--;
2005 }
2006
2007 if (p->accept_ra_types == RA_ANY)
ca34698c 2008 for(e = n->routes; e; e = e->next)
23ac9e9a 2009 {
0c791f87 2010 if (p->export_state != ES_FEEDING)
23ac9e9a 2011 return 1; /* In the meantime, the protocol fell down. */
ca34698c
OZ
2012
2013 if (!rte_is_valid(e))
2014 continue;
2015
23ac9e9a
OZ
2016 do_feed_baby(p, RA_ANY, h, n, e);
2017 max_feed--;
2018 }
ac5d8012
MM
2019 }
2020 FIB_ITERATE_END(fn);
2021 p->feed_ahook = h->next;
2022 if (!p->feed_ahook)
2023 {
2024 mb_free(p->feed_iterator);
2025 p->feed_iterator = NULL;
2026 return 1;
2027 }
2028
2029next_hook:
2030 h = p->feed_ahook;
2031 FIB_ITERATE_INIT(fit, &h->table->fib);
2032 goto again;
2033}
2034
58740ed4
MM
2035/**
2036 * rt_feed_baby_abort - abort protocol feeding
2037 * @p: protocol
2038 *
2039 * This function is called by the protocol code when the protocol
2040 * stops or ceases to exist before the last iteration of rt_feed_baby()
2041 * has finished.
2042 */
ac5d8012
MM
2043void
2044rt_feed_baby_abort(struct proto *p)
2045{
2046 if (p->feed_ahook)
2047 {
2048 /* Unlink the iterator and exit */
2049 fit_get(&p->feed_ahook->table->fib, p->feed_iterator);
2050 p->feed_ahook = NULL;
2051 }
2052}
2053
f2b76f2c
OZ
2054
2055static inline unsigned
2056ptr_hash(void *ptr)
2057{
2058 uintptr_t p = (uintptr_t) ptr;
2059 return p ^ (p << 8) ^ (p >> 16);
2060}
2061
2062static inline unsigned
2063hc_hash(ip_addr a, rtable *dep)
2064{
2065 return (ipa_hash(a) ^ ptr_hash(dep)) & 0xffff;
2066}
2067
2068static inline void
2069hc_insert(struct hostcache *hc, struct hostentry *he)
2070{
ae80a2de 2071 uint k = he->hash_key >> hc->hash_shift;
f2b76f2c
OZ
2072 he->next = hc->hash_table[k];
2073 hc->hash_table[k] = he;
2074}
2075
2076static inline void
2077hc_remove(struct hostcache *hc, struct hostentry *he)
2078{
2079 struct hostentry **hep;
ae80a2de 2080 uint k = he->hash_key >> hc->hash_shift;
f2b76f2c
OZ
2081
2082 for (hep = &hc->hash_table[k]; *hep != he; hep = &(*hep)->next);
2083 *hep = he->next;
2084}
2085
2086#define HC_DEF_ORDER 10
2087#define HC_HI_MARK *4
2088#define HC_HI_STEP 2
2089#define HC_HI_ORDER 16 /* Must be at most 16 */
2090#define HC_LO_MARK /5
2091#define HC_LO_STEP 2
2092#define HC_LO_ORDER 10
2093
2094static void
2095hc_alloc_table(struct hostcache *hc, unsigned order)
2096{
2097 unsigned hsize = 1 << order;
2098 hc->hash_order = order;
2099 hc->hash_shift = 16 - order;
2100 hc->hash_max = (order >= HC_HI_ORDER) ? ~0 : (hsize HC_HI_MARK);
2101 hc->hash_min = (order <= HC_LO_ORDER) ? 0 : (hsize HC_LO_MARK);
2102
2103 hc->hash_table = mb_allocz(rt_table_pool, hsize * sizeof(struct hostentry *));
2104}
2105
cfe34a31 2106static void
f2b76f2c 2107hc_resize(struct hostcache *hc, unsigned new_order)
cfe34a31 2108{
f2b76f2c
OZ
2109 unsigned old_size = 1 << hc->hash_order;
2110 struct hostentry **old_table = hc->hash_table;
2111 struct hostentry *he, *hen;
2112 int i;
2113
2114 hc_alloc_table(hc, new_order);
2115 for (i = 0; i < old_size; i++)
2116 for (he = old_table[i]; he != NULL; he=hen)
2117 {
2118 hen = he->next;
2119 hc_insert(hc, he);
2120 }
2121 mb_free(old_table);
2122}
2123
2124static struct hostentry *
1b180121 2125hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsigned k)
f2b76f2c
OZ
2126{
2127 struct hostentry *he = sl_alloc(hc->slab);
2128
2129 he->addr = a;
1b180121 2130 he->link = ll;
f2b76f2c
OZ
2131 he->tab = dep;
2132 he->hash_key = k;
2133 he->uc = 0;
7e95c05d 2134 he->src = NULL;
f2b76f2c
OZ
2135
2136 add_tail(&hc->hostentries, &he->ln);
2137 hc_insert(hc, he);
2138
2139 hc->hash_items++;
2140 if (hc->hash_items > hc->hash_max)
2141 hc_resize(hc, hc->hash_order + HC_HI_STEP);
2142
2143 return he;
2144}
2145
2146static void
2147hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)
2148{
7e95c05d
OZ
2149 rta_free(he->src);
2150
f2b76f2c
OZ
2151 rem_node(&he->ln);
2152 hc_remove(hc, he);
2153 sl_free(hc->slab, he);
2154
2155 hc->hash_items--;
2156 if (hc->hash_items < hc->hash_min)
2157 hc_resize(hc, hc->hash_order - HC_LO_STEP);
cfe34a31
OZ
2158}
2159
2160static void
2161rt_init_hostcache(rtable *tab)
2162{
2163 struct hostcache *hc = mb_allocz(rt_table_pool, sizeof(struct hostcache));
2164 init_list(&hc->hostentries);
f2b76f2c
OZ
2165
2166 hc->hash_items = 0;
2167 hc_alloc_table(hc, HC_DEF_ORDER);
2168 hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
2169
c477f489 2170 hc->lp = lp_new(rt_table_pool, 1008);
51762a45 2171 hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
c477f489 2172
cfe34a31
OZ
2173 tab->hostcache = hc;
2174}
2175
2176static void
2177rt_free_hostcache(rtable *tab)
2178{
2179 struct hostcache *hc = tab->hostcache;
2180
2181 node *n;
2182 WALK_LIST(n, hc->hostentries)
2183 {
2184 struct hostentry *he = SKIP_BACK(struct hostentry, ln, n);
7e95c05d
OZ
2185 rta_free(he->src);
2186
cfe34a31
OZ
2187 if (he->uc)
2188 log(L_ERR "Hostcache is not empty in table %s", tab->name);
2189 }
2190
f2b76f2c 2191 rfree(hc->slab);
c477f489 2192 rfree(hc->lp);
f2b76f2c 2193 mb_free(hc->hash_table);
cfe34a31
OZ
2194 mb_free(hc);
2195}
2196
2197static void
2198rt_notify_hostcache(rtable *tab, net *net)
2199{
2200 struct hostcache *hc = tab->hostcache;
2201
2202 if (tab->hcu_scheduled)
2203 return;
2204
c477f489
OZ
2205 if (trie_match_prefix(hc->trie, net->n.prefix, net->n.pxlen))
2206 rt_schedule_hcu(tab);
cfe34a31
OZ
2207}
2208
2209static int
2210if_local_addr(ip_addr a, struct iface *i)
2211{
2212 struct ifa *b;
2213
2214 WALK_LIST(b, i->addrs)
2215 if (ipa_equal(a, b->ip))
2216 return 1;
2217
2218 return 0;
2219}
2220
d1e146f2
OZ
2221static u32
2222rt_get_igp_metric(rte *rt)
2223{
ba5e5940
OZ
2224 eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
2225
2226 if (ea)
2227 return ea->u.data;
2228
d1e146f2 2229 rta *a = rt->attrs;
b7c48981
OF
2230
2231#ifdef CONFIG_OSPF
d1e146f2
OZ
2232 if ((a->source == RTS_OSPF) ||
2233 (a->source == RTS_OSPF_IA) ||
2234 (a->source == RTS_OSPF_EXT1))
2235 return rt->u.ospf.metric1;
b7c48981 2236#endif
d1e146f2 2237
b7c48981 2238#ifdef CONFIG_RIP
d1e146f2
OZ
2239 if (a->source == RTS_RIP)
2240 return rt->u.rip.metric;
b7c48981 2241#endif
d1e146f2
OZ
2242
2243 /* Device routes */
7e95c05d 2244 if ((a->dest != RTD_ROUTER) && (a->dest != RTD_MULTIPATH))
d1e146f2
OZ
2245 return 0;
2246
2247 return IGP_METRIC_UNKNOWN;
2248}
2249
cfe34a31
OZ
2250static int
2251rt_update_hostentry(rtable *tab, struct hostentry *he)
2252{
7e95c05d 2253 rta *old_src = he->src;
c477f489 2254 int pxlen = 0;
cfe34a31 2255
7e95c05d
OZ
2256 /* Reset the hostentry */
2257 he->src = NULL;
2258 he->gw = IPA_NONE;
2259 he->dest = RTD_UNREACHABLE;
2260 he->igp_metric = 0;
2261
d1e146f2
OZ
2262 net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH);
2263 if (n)
cfe34a31 2264 {
cf98be7b
OZ
2265 rte *e = n->routes;
2266 rta *a = e->attrs;
c477f489 2267 pxlen = n->n.pxlen;
cfe34a31 2268
2c9033af
OZ
2269 if (a->hostentry)
2270 {
2271 /* Recursive route should not depend on another recursive route */
2272 log(L_WARN "Next hop address %I resolvable through recursive route for %I/%d",
7e95c05d
OZ
2273 he->addr, n->n.prefix, pxlen);
2274 goto done;
2c9033af 2275 }
7e95c05d
OZ
2276
2277 if (a->dest == RTD_DEVICE)
cfe34a31 2278 {
f2b76f2c 2279 if (if_local_addr(he->addr, a->iface))
cfe34a31
OZ
2280 {
2281 /* The host address is a local address, this is not valid */
2282 log(L_WARN "Next hop address %I is a local address of iface %s",
f2b76f2c 2283 he->addr, a->iface->name);
7e95c05d 2284 goto done;
cfe34a31 2285 }
7e95c05d
OZ
2286
2287 /* The host is directly reachable, use link as a gateway */
2288 he->gw = he->link;
2289 he->dest = RTD_ROUTER;
cfe34a31
OZ
2290 }
2291 else
2292 {
2293 /* The host is reachable through some route entry */
cfe34a31
OZ
2294 he->gw = a->gw;
2295 he->dest = a->dest;
2296 }
d1e146f2 2297
7e95c05d 2298 he->src = rta_clone(a);
cf98be7b 2299 he->igp_metric = rt_get_igp_metric(e);
cfe34a31
OZ
2300 }
2301
7e95c05d 2302 done:
c477f489
OZ
2303 /* Add a prefix range to the trie */
2304 trie_add_prefix(tab->hostcache->trie, he->addr, MAX_PREFIX_LENGTH, pxlen, MAX_PREFIX_LENGTH);
2305
7e95c05d
OZ
2306 rta_free(old_src);
2307 return old_src != he->src;
cfe34a31
OZ
2308}
2309
2310static void
2311rt_update_hostcache(rtable *tab)
2312{
2313 struct hostcache *hc = tab->hostcache;
2314 struct hostentry *he;
2315 node *n, *x;
2316
c477f489
OZ
2317 /* Reset the trie */
2318 lp_flush(hc->lp);
51762a45 2319 hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
c477f489 2320
cfe34a31
OZ
2321 WALK_LIST_DELSAFE(n, x, hc->hostentries)
2322 {
2323 he = SKIP_BACK(struct hostentry, ln, n);
2324 if (!he->uc)
2325 {
f2b76f2c 2326 hc_delete_hostentry(hc, he);
cfe34a31
OZ
2327 continue;
2328 }
2329
2330 if (rt_update_hostentry(tab, he))
2331 rt_schedule_nhu(he->tab);
2332 }
2333
2334 tab->hcu_scheduled = 0;
2335}
2336
2337static struct hostentry *
094d2bdb 2338rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
cfe34a31
OZ
2339{
2340 struct hostentry *he;
2341
2342 if (!tab->hostcache)
2343 rt_init_hostcache(tab);
2344
ae80a2de 2345 uint k = hc_hash(a, dep);
f2b76f2c
OZ
2346 struct hostcache *hc = tab->hostcache;
2347 for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next)
2348 if (ipa_equal(he->addr, a) && (he->tab == dep))
2349 return he;
cfe34a31 2350
1b180121 2351 he = hc_new_hostentry(hc, a, ll, dep, k);
f2b76f2c 2352 rt_update_hostentry(tab, he);
cfe34a31
OZ
2353 return he;
2354}
2355
2356void
1b180121 2357rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll)
cfe34a31 2358{
094d2bdb 2359 rta_apply_hostentry(a, rt_get_hostentry(tab, *gw, *ll, dep));
cfe34a31
OZ
2360}
2361
094d2bdb 2362
730f2e2c
MM
2363/*
2364 * CLI commands
2365 */
2366
2367static void
cfd46ee4 2368rt_format_via(rte *e, byte *via)
730f2e2c 2369{
730f2e2c
MM
2370 rta *a = e->attrs;
2371
2372 switch (a->dest)
2373 {
2374 case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break;
2375 case RTD_DEVICE: bsprintf(via, "dev %s", a->iface->name); break;
2376 case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break;
2377 case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
2378 case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
7e95c05d 2379 case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
730f2e2c
MM
2380 default: bsprintf(via, "???");
2381 }
cfd46ee4
MM
2382}
2383
2384static void
ce1da96e 2385rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa)
cfd46ee4 2386{
4ca93a50 2387 byte via[STD_ADDRESS_P_LENGTH+32], from[STD_ADDRESS_P_LENGTH+8];
c37e7851 2388 byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
cfd46ee4 2389 rta *a = e->attrs;
5a56f27c 2390 int primary = (e->net->routes == e);
32f95476 2391 int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
094d2bdb 2392 void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
7e95c05d 2393 struct mpnh *nh;
cfd46ee4
MM
2394
2395 rt_format_via(e, via);
c37e7851 2396 tm_format_datetime(tm, &config->tf_route, e->lastmod);
730f2e2c
MM
2397 if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw))
2398 bsprintf(from, " from %I", a->from);
2399 else
2400 from[0] = 0;
094d2bdb
OZ
2401
2402 get_route_info = a->src->proto->proto->get_route_info;
2403 if (get_route_info || d->verbose)
ce1da96e
MM
2404 {
2405 /* Need to normalize the extended attributes */
2406 ea_list *t = tmpa;
2407 t = ea_append(t, a->eattrs);
2408 tmpa = alloca(ea_scan(t));
2409 ea_merge(t, tmpa);
2f711231 2410 ea_sort(tmpa);
ce1da96e 2411 }
094d2bdb
OZ
2412 if (get_route_info)
2413 get_route_info(e, info, tmpa);
730f2e2c
MM
2414 else
2415 bsprintf(info, " (%d)", e->pref);
094d2bdb 2416 cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->src->proto->name,
32f95476 2417 tm, from, primary ? (sync_error ? " !" : " *") : "", info);
7e95c05d
OZ
2418 for (nh = a->nexthops; nh; nh = nh->next)
2419 cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1);
730f2e2c 2420 if (d->verbose)
ce1da96e 2421 rta_show(c, a, tmpa);
730f2e2c
MM
2422}
2423
2424static void
2425rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
2426{
2427 rte *e, *ee;
2428 byte ia[STD_ADDRESS_P_LENGTH+8];
c865cae3
OZ
2429 struct ea_list *tmpa;
2430 struct announce_hook *a = NULL;
2431 int first = 1;
2432 int pass = 0;
730f2e2c
MM
2433
2434 bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen);
cf98be7b 2435
c865cae3
OZ
2436 if (d->export_mode)
2437 {
7aa80901
OZ
2438 if (! d->export_protocol->rt_notify)
2439 return;
2440
c865cae3
OZ
2441 a = proto_find_announce_hook(d->export_protocol, d->table);
2442 if (!a)
2443 return;
2444 }
2445
2446 for (e = n->routes; e; e = e->next)
730f2e2c 2447 {
15550957 2448 if (rte_is_filtered(e) != d->filtered)
cf98be7b
OZ
2449 continue;
2450
23693958 2451 d->rt_counter++;
c865cae3
OZ
2452 d->net_counter += first;
2453 first = 0;
2454
2455 if (pass)
2456 continue;
2457
730f2e2c
MM
2458 ee = e;
2459 rte_update_lock(); /* We use the update buffer for filtering */
094d2bdb 2460 tmpa = make_tmp_attrs(e, rte_update_pool);
c865cae3 2461
8d9eef17
OZ
2462 /* Special case for merged export */
2463 if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED))
2464 {
2465 rte *rt_free;
2466 e = rt_export_merged(a, n, &rt_free, &tmpa, 1);
2467 pass = 1;
2468
2469 if (!e)
2470 { e = ee; goto skip; }
2471 }
2472 else if (d->export_mode)
ce1da96e 2473 {
c865cae3
OZ
2474 struct proto *ep = d->export_protocol;
2475 int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0;
2476
8d9eef17 2477 if (ep->accept_ra_types == RA_OPTIMAL || ep->accept_ra_types == RA_MERGED)
c865cae3
OZ
2478 pass = 1;
2479
2480 if (ic < 0)
2481 goto skip;
2482
7aa80901 2483 if (d->export_mode > RSEM_PREEXPORT)
ce1da96e 2484 {
c865cae3
OZ
2485 /*
2486 * FIXME - This shows what should be exported according to current
2487 * filters, but not what was really exported. 'configure soft'
2488 * command may change the export filter and do not update routes.
2489 */
7aa80901
OZ
2490 int do_export = (ic > 0) ||
2491 (f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
c865cae3 2492
7aa80901 2493 if (do_export != (d->export_mode == RSEM_EXPORT))
c865cae3
OZ
2494 goto skip;
2495
7aa80901 2496 if ((d->export_mode == RSEM_EXPORT) && (ep->accept_ra_types == RA_ACCEPTED))
c865cae3 2497 pass = 1;
ce1da96e
MM
2498 }
2499 }
c865cae3
OZ
2500
2501 if (d->show_protocol && (d->show_protocol != e->attrs->src->proto))
2502 goto skip;
2503
2504 if (f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
2505 goto skip;
2506
2507 d->show_counter++;
2508 if (d->stats < 2)
2509 rt_show_rte(c, ia, e, d, tmpa);
2510 ia[0] = 0;
2511
2512 skip:
730f2e2c 2513 if (e != ee)
5e9bdac2
OZ
2514 {
2515 rte_free(e);
2516 e = ee;
2517 }
730f2e2c 2518 rte_update_unlock();
c865cae3 2519
0117d004 2520 if (d->primary_only)
ce1da96e 2521 break;
730f2e2c
MM
2522 }
2523}
2524
2525static void
2526rt_show_cont(struct cli *c)
2527{
2528 struct rt_show_data *d = c->rover;
f098e072
MM
2529#ifdef DEBUGGING
2530 unsigned max = 4;
2531#else
2532 unsigned max = 64;
2533#endif
730f2e2c
MM
2534 struct fib *fib = &d->table->fib;
2535 struct fib_iterator *it = &d->fit;
2536
2537 FIB_ITERATE_START(fib, it, f)
2538 {
2539 net *n = (net *) f;
ce1da96e
MM
2540 if (d->running_on_config && d->running_on_config != config)
2541 {
2542 cli_printf(c, 8004, "Stopped due to reconfiguration");
2543 goto done;
2544 }
0c791f87 2545 if (d->export_protocol && (d->export_protocol->export_state == ES_DOWN))
ce1da96e
MM
2546 {
2547 cli_printf(c, 8005, "Protocol is down");
2548 goto done;
2549 }
730f2e2c
MM
2550 if (!max--)
2551 {
2552 FIB_ITERATE_PUT(it, f);
2553 return;
2554 }
2555 rt_show_net(c, n, d);
2556 }
2557 FIB_ITERATE_END(f);
23693958
MM
2558 if (d->stats)
2559 cli_printf(c, 14, "%d of %d routes for %d networks", d->show_counter, d->rt_counter, d->net_counter);
2560 else
2561 cli_printf(c, 0, "");
ce1da96e 2562done:
730f2e2c
MM
2563 c->cont = c->cleanup = NULL;
2564}
2565
2566static void
2567rt_show_cleanup(struct cli *c)
2568{
2569 struct rt_show_data *d = c->rover;
2570
2571 /* Unlink the iterator */
2572 fit_get(&d->table->fib, &d->fit);
2573}
2574
2575void
2576rt_show(struct rt_show_data *d)
2577{
730f2e2c
MM
2578 net *n;
2579
e667622a 2580 /* Default is either a master table or a table related to a respective protocol */
c865cae3
OZ
2581 if (!d->table && d->export_protocol) d->table = d->export_protocol->table;
2582 if (!d->table && d->show_protocol) d->table = d->show_protocol->table;
e667622a
OF
2583 if (!d->table) d->table = config->master_rtc->table;
2584
c865cae3
OZ
2585 /* Filtered routes are neither exported nor have sensible ordering */
2586 if (d->filtered && (d->export_mode || d->primary_only))
2587 cli_msg(0, "");
2588
730f2e2c
MM
2589 if (d->pxlen == 256)
2590 {
2591 FIB_ITERATE_INIT(&d->fit, &d->table->fib);
2592 this_cli->cont = rt_show_cont;
2593 this_cli->cleanup = rt_show_cleanup;
2594 this_cli->rover = d;
2595 }
2596 else
2597 {
9449c91a 2598 if (d->show_for)
d1e146f2 2599 n = net_route(d->table, d->prefix, d->pxlen);
9449c91a 2600 else
d1e146f2 2601 n = net_find(d->table, d->prefix, d->pxlen);
0da562a7 2602
730f2e2c 2603 if (n)
0da562a7
OZ
2604 rt_show_net(this_cli, n, d);
2605
2606 if (d->rt_counter)
2607 cli_msg(0, "");
730f2e2c
MM
2608 else
2609 cli_msg(8001, "Network not in table");
2610 }
2611}
3ce8c610
MM
2612
2613/*
2614 * Documentation for functions declared inline in route.h
2615 */
2616#if 0
2617
2618/**
2619 * net_find - find a network entry
2620 * @tab: a routing table
2621 * @addr: address of the network
2622 * @len: length of the network prefix
2623 *
2624 * net_find() looks up the given network in routing table @tab and
2625 * returns a pointer to its &net entry or %NULL if no such network
2626 * exists.
2627 */
2628static inline net *net_find(rtable *tab, ip_addr addr, unsigned len)
2629{ DUMMY; }
2630
2631/**
2632 * net_get - obtain a network entry
2633 * @tab: a routing table
2634 * @addr: address of the network
2635 * @len: length of the network prefix
2636 *
2637 * net_get() looks up the given network in routing table @tab and
2638 * returns a pointer to its &net entry. If no such entry exists, it's
2639 * created.
2640 */
2641static inline net *net_get(rtable *tab, ip_addr addr, unsigned len)
2642{ DUMMY; }
2643
2644/**
2645 * rte_cow - copy a route for writing
2646 * @r: a route entry to be copied
2647 *
2648 * rte_cow() takes a &rte and prepares it for modification. The exact action
2649 * taken depends on the flags of the &rte -- if it's a temporary entry, it's
2650 * just returned unchanged, else a new temporary entry with the same contents
2651 * is created.
2652 *
2653 * The primary use of this function is inside the filter machinery -- when
2654 * a filter wants to modify &rte contents (to change the preference or to
2655 * attach another set of attributes), it must ensure that the &rte is not
2656 * shared with anyone else (and especially that it isn't stored in any routing
2657 * table).
2658 *
2e9b2421 2659 * Result: a pointer to the new writable &rte.
3ce8c610
MM
2660 */
2661static inline rte * rte_cow(rte *r)
2662{ DUMMY; }
2663
2664#endif