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