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