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