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