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