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