]> git.ipfire.org Git - thirdparty/bird.git/blame - nest/rt-attr.c
MPLS subsystem
[thirdparty/bird.git] / nest / rt-attr.c
CommitLineData
2326b001
MM
1/*
2 * BIRD -- Route Attribute Cache
3 *
ee76a92a 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
2326b001
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
3ce8c610
MM
9/**
10 * DOC: Route attribute cache
11 *
12 * Each route entry carries a set of route attributes. Several of them
13 * vary from route to route, but most attributes are usually common
14 * for a large number of routes. To conserve memory, we've decided to
15 * store only the varying ones directly in the &rte and hold the rest
16 * in a special structure called &rta which is shared among all the
17 * &rte's with these attributes.
18 *
19 * Each &rta contains all the static attributes of the route (i.e.,
20 * those which are always present) as structure members and a list of
21 * dynamic attributes represented by a linked list of &ea_list
22 * structures, each of them consisting of an array of &eattr's containing
23 * the individual attributes. An attribute can be specified more than once
2e9b2421 24 * in the &ea_list chain and in such case the first occurrence overrides
3ce8c610
MM
25 * the others. This semantics is used especially when someone (for example
26 * a filter) wishes to alter values of several dynamic attributes, but
27 * it wants to preserve the original attribute lists maintained by
28 * another module.
29 *
30 * Each &eattr contains an attribute identifier (split to protocol ID and
31 * per-protocol attribute ID), protocol dependent flags, a type code (consisting
32 * of several bit fields describing attribute characteristics) and either an
33 * embedded 32-bit value or a pointer to a &adata structure holding attribute
34 * contents.
35 *
2e9b2421 36 * There exist two variants of &rta's -- cached and un-cached ones. Un-cached
3ce8c610
MM
37 * &rta's can have arbitrarily complex structure of &ea_list's and they
38 * can be modified by any module in the route processing chain. Cached
39 * &rta's have their attribute lists normalized (that means at most one
40 * &ea_list is present and its values are sorted in order to speed up
41 * searching), they are stored in a hash table to make fast lookup possible
42 * and they are provided with a use count to allow sharing.
43 *
44 * Routing tables always contain only cached &rta's.
45 */
46
2326b001
MM
47#include "nest/bird.h"
48#include "nest/route.h"
49#include "nest/protocol.h"
66e53309 50#include "nest/iface.h"
730f2e2c 51#include "nest/cli.h"
c6add07f 52#include "nest/attrs.h"
10af3676 53#include "lib/alloca.h"
e7d2ac44 54#include "lib/hash.h"
74c838a8 55#include "lib/idm.h"
2326b001 56#include "lib/resource.h"
221135d6 57#include "lib/string.h"
2326b001 58
9a74622c
JMM
59#include <stddef.h>
60
4c553c5a
MM
61const adata null_adata; /* adata of length 0 */
62
69b2f63d 63const char * const rta_src_names[RTS_MAX] = {
69b2f63d
OZ
64 [RTS_STATIC] = "static",
65 [RTS_INHERIT] = "inherit",
66 [RTS_DEVICE] = "device",
67 [RTS_STATIC_DEVICE] = "static-device",
68 [RTS_REDIRECT] = "redirect",
69 [RTS_RIP] = "RIP",
70 [RTS_OSPF] = "OSPF",
71 [RTS_OSPF_IA] = "OSPF-IA",
72 [RTS_OSPF_EXT1] = "OSPF-E1",
73 [RTS_OSPF_EXT2] = "OSPF-E2",
74 [RTS_BGP] = "BGP",
75 [RTS_PIPE] = "pipe",
76 [RTS_BABEL] = "Babel",
77 [RTS_RPKI] = "RPKI",
977b82fb
IP
78 [RTS_PERF] = "Perf",
79 [RTS_AGGREGATED] = "aggregated",
69b2f63d
OZ
80};
81
665be7f6
OZ
82const char * rta_dest_names[RTD_MAX] = {
83 [RTD_NONE] = "",
84 [RTD_UNICAST] = "unicast",
85 [RTD_BLACKHOLE] = "blackhole",
86 [RTD_UNREACHABLE] = "unreachable",
87 [RTD_PROHIBIT] = "prohibited",
88};
89
acb60628
OZ
90pool *rta_pool;
91
ec5e5d23
JMM
92static slab *rta_slab_[4];
93static slab *nexthop_slab_[4];
094d2bdb
OZ
94static slab *rte_src_slab;
95
74c838a8 96static struct idm src_ids;
e7d2ac44 97#define SRC_ID_INIT_SIZE 4
094d2bdb
OZ
98
99/* rte source hash */
e7d2ac44
OZ
100
101#define RSH_KEY(n) n->proto, n->private_id
102#define RSH_NEXT(n) n->next
103#define RSH_EQ(p1,n1,p2,n2) p1 == p2 && n1 == n2
21213be5 104#define RSH_FN(p,n) p->hash_key ^ u64_hash(n)
e7d2ac44
OZ
105
106#define RSH_REHASH rte_src_rehash
107#define RSH_PARAMS /2, *2, 1, 1, 8, 20
108#define RSH_INIT_ORDER 6
109
110static HASH(struct rte_src) src_hash;
2326b001 111
094d2bdb
OZ
112static void
113rte_src_init(void)
114{
115 rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src));
116
74c838a8 117 idm_init(&src_ids, rta_pool, SRC_ID_INIT_SIZE);
094d2bdb 118
e7d2ac44 119 HASH_INIT(src_hash, rta_pool, RSH_INIT_ORDER);
094d2bdb
OZ
120}
121
094d2bdb 122
e7d2ac44 123HASH_DEFINE_REHASH_FN(RSH, struct rte_src)
094d2bdb
OZ
124
125struct rte_src *
126rt_find_source(struct proto *p, u32 id)
127{
e7d2ac44 128 return HASH_FIND(src_hash, RSH, p, id);
094d2bdb
OZ
129}
130
131struct rte_src *
132rt_get_source(struct proto *p, u32 id)
133{
e7d2ac44 134 struct rte_src *src = rt_find_source(p, id);
094d2bdb 135
e7d2ac44
OZ
136 if (src)
137 return src;
094d2bdb 138
c9ae8165 139 src = sl_allocz(rte_src_slab);
094d2bdb
OZ
140 src->proto = p;
141 src->private_id = id;
74c838a8 142 src->global_id = idm_alloc(&src_ids);
094d2bdb 143 src->uc = 0;
d217ba51 144
e7d2ac44 145 HASH_INSERT2(src_hash, RSH, rta_pool, src);
094d2bdb
OZ
146
147 return src;
148}
149
094d2bdb
OZ
150void
151rt_prune_sources(void)
152{
e7d2ac44
OZ
153 HASH_WALK_FILTER(src_hash, next, src, sp)
154 {
155 if (src->uc == 0)
094d2bdb 156 {
e7d2ac44 157 HASH_DO_REMOVE(src_hash, RSH, sp);
74c838a8 158 idm_free(&src_ids, src->global_id);
ebd807c0 159 sl_free(src);
094d2bdb 160 }
e7d2ac44
OZ
161 }
162 HASH_WALK_FILTER_END;
094d2bdb 163
e7d2ac44 164 HASH_MAY_RESIZE_DOWN(src_hash, RSH, rta_pool);
094d2bdb
OZ
165}
166
167
168/*
169 * Multipath Next Hop
170 */
171
04632fd7 172static inline u32
4e276a89 173nexthop_hash(struct nexthop *x)
7e95c05d 174{
04632fd7 175 u32 h = 0;
7e95c05d 176 for (; x; x = x->next)
ec5e5d23
JMM
177 {
178 h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9);
62e64905
OZ
179
180 for (int i = 0; i < x->labels; i++)
ec5e5d23
JMM
181 h ^= x->label[i] ^ (h << 6) ^ (h >> 7);
182 }
7e95c05d
OZ
183
184 return h;
185}
186
187int
4e276a89 188nexthop__same(struct nexthop *x, struct nexthop *y)
7e95c05d
OZ
189{
190 for (; x && y; x = x->next, y = y->next)
ec5e5d23 191 {
a1f5e514
OZ
192 if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
193 (x->flags != y->flags) || (x->weight != y->weight) ||
bda58634 194 (x->labels_orig != y->labels_orig) || (x->labels != y->labels))
7e95c05d 195 return 0;
62e64905
OZ
196
197 for (int i = 0; i < x->labels; i++)
ec5e5d23
JMM
198 if (x->label[i] != y->label[i])
199 return 0;
200 }
7e95c05d 201
62e64905 202 return x == y;
7e95c05d
OZ
203}
204
d217ba51 205static int
0fa8bf91 206nexthop_compare_node(const struct nexthop *x, const struct nexthop *y)
d217ba51
OZ
207{
208 int r;
209
210 if (!x)
211 return 1;
212
213 if (!y)
214 return -1;
215
a1f5e514
OZ
216 /* Should we also compare flags ? */
217
d217ba51
OZ
218 r = ((int) y->weight) - ((int) x->weight);
219 if (r)
220 return r;
221
222 r = ipa_compare(x->gw, y->gw);
223 if (r)
224 return r;
225
ec5e5d23
JMM
226 r = ((int) y->labels) - ((int) x->labels);
227 if (r)
228 return r;
229
62e64905 230 for (int i = 0; i < y->labels; i++)
ec5e5d23
JMM
231 {
232 r = ((int) y->label[i]) - ((int) x->label[i]);
233 if (r)
234 return r;
235 }
236
d217ba51
OZ
237 return ((int) x->iface->index) - ((int) y->iface->index);
238}
239
4e276a89
JMM
240static inline struct nexthop *
241nexthop_copy_node(const struct nexthop *src, linpool *lp)
d217ba51 242{
ec5e5d23
JMM
243 struct nexthop *n = lp_alloc(lp, nexthop_size(src));
244
245 memcpy(n, src, nexthop_size(src));
d217ba51 246 n->next = NULL;
ec5e5d23 247
d217ba51
OZ
248 return n;
249}
250
251/**
4e276a89 252 * nexthop_merge - merge nexthop lists
d217ba51
OZ
253 * @x: list 1
254 * @y: list 2
255 * @rx: reusability of list @x
256 * @ry: reusability of list @y
257 * @max: max number of nexthops
258 * @lp: linpool for allocating nexthops
259 *
4e276a89 260 * The nexthop_merge() function takes two nexthop lists @x and @y and merges them,
d217ba51
OZ
261 * eliminating possible duplicates. The input lists must be sorted and the
262 * result is sorted too. The number of nexthops in result is limited by @max.
263 * New nodes are allocated from linpool @lp.
264 *
265 * The arguments @rx and @ry specify whether corresponding input lists may be
266 * consumed by the function (i.e. their nodes reused in the resulting list), in
267 * that case the caller should not access these lists after that. To eliminate
268 * issues with deallocation of these lists, the caller should use some form of
269 * bulk deallocation (e.g. stack or linpool) to free these nodes when the
270 * resulting list is no longer needed. When reusability is not set, the
271 * corresponding lists are not modified nor linked from the resulting list.
272 */
4e276a89
JMM
273struct nexthop *
274nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp)
d217ba51 275{
4e276a89
JMM
276 struct nexthop *root = NULL;
277 struct nexthop **n = &root;
d217ba51
OZ
278
279 while ((x || y) && max--)
280 {
4e276a89 281 int cmp = nexthop_compare_node(x, y);
0fa8bf91 282
d217ba51
OZ
283 if (cmp < 0)
284 {
0fa8bf91 285 ASSUME(x);
4e276a89 286 *n = rx ? x : nexthop_copy_node(x, lp);
d217ba51
OZ
287 x = x->next;
288 }
289 else if (cmp > 0)
290 {
0fa8bf91 291 ASSUME(y);
4e276a89 292 *n = ry ? y : nexthop_copy_node(y, lp);
d217ba51
OZ
293 y = y->next;
294 }
295 else
296 {
0fa8bf91 297 ASSUME(x && y);
4e276a89 298 *n = rx ? x : (ry ? y : nexthop_copy_node(x, lp));
d217ba51
OZ
299 x = x->next;
300 y = y->next;
301 }
302 n = &((*n)->next);
303 }
304 *n = NULL;
305
306 return root;
307}
308
84cac51a 309void
62e64905 310nexthop_insert(struct nexthop **n, struct nexthop *x)
84cac51a 311{
62e64905 312 for (; *n; n = &((*n)->next))
4e276a89 313 {
62e64905 314 int cmp = nexthop_compare_node(*n, x);
84cac51a
OZ
315
316 if (cmp < 0)
317 continue;
62e64905
OZ
318 else if (cmp > 0)
319 break;
320 else
321 return;
84cac51a
OZ
322 }
323
62e64905
OZ
324 x->next = *n;
325 *n = x;
84cac51a
OZ
326}
327
59d3a361
OZ
328struct nexthop *
329nexthop_sort(struct nexthop *x)
330{
331 struct nexthop *s = NULL;
332
333 /* Simple insert-sort */
334 while (x)
335 {
336 struct nexthop *n = x;
337 x = n->next;
338 n->next = NULL;
339
340 nexthop_insert(&s, n);
341 }
342
343 return s;
344}
345
84cac51a 346int
4e276a89 347nexthop_is_sorted(struct nexthop *x)
84cac51a
OZ
348{
349 for (; x && x->next; x = x->next)
4e276a89 350 if (nexthop_compare_node(x, x->next) >= 0)
84cac51a
OZ
351 return 0;
352
353 return 1;
354}
d217ba51 355
ec5e5d23
JMM
356static inline slab *
357nexthop_slab(struct nexthop *nh)
358{
62e64905 359 return nexthop_slab_[MIN(nh->labels, 3)];
ec5e5d23
JMM
360}
361
4e276a89
JMM
362static struct nexthop *
363nexthop_copy(struct nexthop *o)
7e95c05d 364{
4e276a89
JMM
365 struct nexthop *first = NULL;
366 struct nexthop **last = &first;
7e95c05d
OZ
367
368 for (; o; o = o->next)
369 {
c9ae8165 370 struct nexthop *n = sl_allocz(nexthop_slab(o));
7e95c05d
OZ
371 n->gw = o->gw;
372 n->iface = o->iface;
373 n->next = NULL;
33716595 374 n->flags = o->flags;
7e95c05d 375 n->weight = o->weight;
bda58634 376 n->labels_orig = o->labels_orig;
f2010f9c
JMM
377 n->labels = o->labels;
378 for (int i=0; i<o->labels; i++)
379 n->label[i] = o->label[i];
7e95c05d
OZ
380
381 *last = n;
382 last = &(n->next);
383 }
384
385 return first;
386}
387
388static void
4e276a89 389nexthop_free(struct nexthop *o)
7e95c05d 390{
4e276a89 391 struct nexthop *n;
7e95c05d
OZ
392
393 while (o)
394 {
395 n = o->next;
ebd807c0 396 sl_free(o);
7e95c05d
OZ
397 o = n;
398 }
399}
400
401
b77ae37d
MM
402/*
403 * Extended Attributes
404 */
405
8d24b689
MM
406static inline eattr *
407ea__find(ea_list *e, unsigned id)
b77ae37d
MM
408{
409 eattr *a;
410 int l, r, m;
411
412 while (e)
413 {
414 if (e->flags & EALF_BISECT)
415 {
416 l = 0;
fee78355 417 r = e->count - 1;
b77ae37d
MM
418 while (l <= r)
419 {
420 m = (l+r) / 2;
421 a = &e->attrs[m];
422 if (a->id == id)
423 return a;
424 else if (a->id < id)
425 l = m+1;
426 else
427 r = m-1;
428 }
429 }
430 else
431 for(m=0; m<e->count; m++)
432 if (e->attrs[m].id == id)
433 return &e->attrs[m];
434 e = e->next;
435 }
436 return NULL;
437}
438
3ce8c610
MM
439/**
440 * ea_find - find an extended attribute
441 * @e: attribute list to search in
442 * @id: attribute ID to search for
443 *
444 * Given an extended attribute list, ea_find() searches for a first
2e9b2421 445 * occurrence of an attribute with specified ID, returning either a pointer
3ce8c610
MM
446 * to its &eattr structure or %NULL if no such attribute exists.
447 */
8d24b689
MM
448eattr *
449ea_find(ea_list *e, unsigned id)
450{
451 eattr *a = ea__find(e, id & EA_CODE_MASK);
452
0f685152 453 if (a && a->undef && !(id & EA_ALLOW_UNDEF))
8d24b689
MM
454 return NULL;
455 return a;
456}
457
9fdf9d29
OZ
458/**
459 * ea_walk - walk through extended attributes
460 * @s: walk state structure
461 * @id: start of attribute ID interval
462 * @max: length of attribute ID interval
463 *
464 * Given an extended attribute list, ea_walk() walks through the list looking
465 * for first occurrences of attributes with ID in specified interval from @id to
466 * (@id + @max - 1), returning pointers to found &eattr structures, storing its
467 * walk state in @s for subsequent calls.
8e433d6a 468 *
9fdf9d29
OZ
469 * The function ea_walk() is supposed to be called in a loop, with initially
470 * zeroed walk state structure @s with filled the initial extended attribute
471 * list, returning one found attribute in each call or %NULL when no other
472 * attribute exists. The extended attribute list or the arguments should not be
473 * modified between calls. The maximum value of @max is 128.
474 */
475eattr *
476ea_walk(struct ea_walk_state *s, uint id, uint max)
477{
478 ea_list *e = s->eattrs;
479 eattr *a = s->ea;
480 eattr *a_max;
481
482 max = id + max;
483
484 if (a)
485 goto step;
486
487 for (; e; e = e->next)
488 {
489 if (e->flags & EALF_BISECT)
490 {
491 int l, r, m;
492
493 l = 0;
494 r = e->count - 1;
495 while (l < r)
496 {
497 m = (l+r) / 2;
498 if (e->attrs[m].id < id)
499 l = m + 1;
500 else
501 r = m;
502 }
503 a = e->attrs + l;
504 }
505 else
506 a = e->attrs;
507
508 step:
509 a_max = e->attrs + e->count;
510 for (; a < a_max; a++)
511 if ((a->id >= id) && (a->id < max))
512 {
513 int n = a->id - id;
514
515 if (BIT32_TEST(s->visited, n))
516 continue;
517
518 BIT32_SET(s->visited, n);
519
0f685152 520 if (a->undef)
9fdf9d29
OZ
521 continue;
522
523 s->eattrs = e;
524 s->ea = a;
525 return a;
526 }
527 else if (e->flags & EALF_BISECT)
528 break;
529 }
530
531 return NULL;
532}
533
3ce8c610
MM
534/**
535 * ea_get_int - fetch an integer attribute
536 * @e: attribute list
537 * @id: attribute ID
538 * @def: default value
539 *
540 * This function is a shortcut for retrieving a value of an integer attribute
541 * by calling ea_find() to find the attribute, extracting its value or returning
542 * a provided default if no such attribute is present.
543 */
6e13df70
MM
544uintptr_t
545ea_get_int(ea_list *e, unsigned id, uintptr_t def)
c0100454
PM
546{
547 eattr *a = ea_find(e, id);
548 if (!a)
549 return def;
550 return a->u.data;
551}
552
b77ae37d
MM
553static inline void
554ea_do_sort(ea_list *e)
555{
556 unsigned n = e->count;
557 eattr *a = e->attrs;
558 eattr *b = alloca(n * sizeof(eattr));
559 unsigned s, ss;
560
561 /* We need to use a stable sorting algorithm, hence mergesort */
562 do
563 {
564 s = ss = 0;
565 while (s < n)
566 {
567 eattr *p, *q, *lo, *hi;
568 p = b;
569 ss = s;
570 *p++ = a[s++];
571 while (s < n && p[-1].id <= a[s].id)
572 *p++ = a[s++];
573 if (s < n)
574 {
575 q = p;
576 *p++ = a[s++];
577 while (s < n && p[-1].id <= a[s].id)
578 *p++ = a[s++];
579 lo = b;
580 hi = q;
581 s = ss;
582 while (lo < q && hi < p)
583 if (lo->id <= hi->id)
584 a[s++] = *lo++;
585 else
586 a[s++] = *hi++;
587 while (lo < q)
588 a[s++] = *lo++;
589 while (hi < p)
590 a[s++] = *hi++;
591 }
592 }
593 }
594 while (ss);
595}
596
13c0be19 597/**
875cc073
OZ
598 * In place discard duplicates and undefs in sorted ea_list. We use stable sort
599 * for this reason.
13c0be19 600 **/
b77ae37d
MM
601static inline void
602ea_do_prune(ea_list *e)
603{
51a183af 604 eattr *s, *d, *l, *s0;
8d24b689
MM
605 int i = 0;
606
13c0be19
JMM
607 s = d = e->attrs; /* Beginning of the list. @s is source, @d is destination. */
608 l = e->attrs + e->count; /* End of the list */
609
610 /* Walk from begin to end. */
8d24b689
MM
611 while (s < l)
612 {
51a183af 613 s0 = s++;
13c0be19 614 /* Find a consecutive block of the same attribute */
51a183af
MM
615 while (s < l && s->id == s[-1].id)
616 s++;
13c0be19
JMM
617
618 /* Now s0 is the most recent version, s[-1] the oldest one */
619 /* Drop undefs */
0f685152 620 if (s0->undef)
13c0be19
JMM
621 continue;
622
13c0be19
JMM
623 /* Copy the newest version to destination */
624 *d = *s0;
625
626 /* Preserve info whether it originated locally */
63cf5d5d
MM
627 d->originated = s[-1].originated;
628
629 /* Not fresh any more, we prefer surstroemming */
630 d->fresh = 0;
13c0be19
JMM
631
632 /* Next destination */
633 d++;
634 i++;
8d24b689 635 }
13c0be19 636
8d24b689 637 e->count = i;
b77ae37d
MM
638}
639
3ce8c610
MM
640/**
641 * ea_sort - sort an attribute list
642 * @e: list to be sorted
643 *
644 * This function takes a &ea_list chain and sorts the attributes
645 * within each of its entries.
646 *
647 * If an attribute occurs multiple times in a single &ea_list,
2e9b2421 648 * ea_sort() leaves only the first (the only significant) occurrence.
3ce8c610 649 */
b77ae37d
MM
650void
651ea_sort(ea_list *e)
652{
653 while (e)
654 {
655 if (!(e->flags & EALF_SORTED))
656 {
657 ea_do_sort(e);
658 ea_do_prune(e);
659 e->flags |= EALF_SORTED;
660 }
b77ae37d 661 if (e->count > 5)
b77ae37d
MM
662 e->flags |= EALF_BISECT;
663 e = e->next;
664 }
665}
666
3ce8c610
MM
667/**
668 * ea_scan - estimate attribute list size
669 * @e: attribute list
670 *
671 * This function calculates an upper bound of the size of
672 * a given &ea_list after merging with ea_merge().
673 */
b77ae37d
MM
674unsigned
675ea_scan(ea_list *e)
676{
677 unsigned cnt = 0;
678
679 while (e)
680 {
681 cnt += e->count;
682 e = e->next;
683 }
684 return sizeof(ea_list) + sizeof(eattr)*cnt;
685}
686
3ce8c610
MM
687/**
688 * ea_merge - merge segments of an attribute list
689 * @e: attribute list
690 * @t: buffer to store the result to
691 *
692 * This function takes a possibly multi-segment attribute list
693 * and merges all of its segments to one.
694 *
695 * The primary use of this function is for &ea_list normalization:
696 * first call ea_scan() to determine how much memory will the result
697 * take, then allocate a buffer (usually using alloca()), merge the
698 * segments with ea_merge() and finally sort and prune the result
699 * by calling ea_sort().
700 */
b77ae37d
MM
701void
702ea_merge(ea_list *e, ea_list *t)
703{
704 eattr *d = t->attrs;
705
706 t->flags = 0;
707 t->count = 0;
708 t->next = NULL;
709 while (e)
710 {
711 memcpy(d, e->attrs, sizeof(eattr)*e->count);
712 t->count += e->count;
713 d += e->count;
714 e = e->next;
715 }
716}
717
3ce8c610
MM
718/**
719 * ea_same - compare two &ea_list's
720 * @x: attribute list
721 * @y: attribute list
722 *
723 * ea_same() compares two normalized attribute lists @x and @y and returns
724 * 1 if they contain the same attributes, 0 otherwise.
725 */
6f57dcc0 726int
2326b001
MM
727ea_same(ea_list *x, ea_list *y)
728{
729 int c;
730
b77ae37d
MM
731 if (!x || !y)
732 return x == y;
733 ASSERT(!x->next && !y->next);
734 if (x->count != y->count)
735 return 0;
736 for(c=0; c<x->count; c++)
2326b001 737 {
b77ae37d
MM
738 eattr *a = &x->attrs[c];
739 eattr *b = &y->attrs[c];
740
741 if (a->id != b->id ||
742 a->flags != b->flags ||
743 a->type != b->type ||
63cf5d5d
MM
744 a->originated != b->originated ||
745 a->fresh != b->fresh ||
0f685152 746 a->undef != b->undef ||
28a10f84 747 ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr)))
2326b001 748 return 0;
b77ae37d
MM
749 }
750 return 1;
751}
752
753static inline ea_list *
754ea_list_copy(ea_list *o)
755{
756 ea_list *n;
7c8b7649 757 unsigned i, adpos, elen;
b77ae37d
MM
758
759 if (!o)
760 return NULL;
761 ASSERT(!o->next);
7c8b7649
MM
762 elen = adpos = sizeof(ea_list) + sizeof(eattr) * o->count;
763
764 for(i=0; i<o->count; i++)
765 {
766 eattr *a = &o->attrs[i];
767 if (!(a->type & EAF_EMBEDDED))
768 elen += sizeof(struct adata) + a->u.ptr->length;
769 }
770
771 n = mb_alloc(rta_pool, elen);
772 memcpy(n, o, adpos);
b77ae37d
MM
773 n->flags |= EALF_CACHED;
774 for(i=0; i<o->count; i++)
775 {
776 eattr *a = &n->attrs[i];
08732b71 777 if (!(a->type & EAF_EMBEDDED))
b77ae37d
MM
778 {
779 unsigned size = sizeof(struct adata) + a->u.ptr->length;
7c8b7649
MM
780 ASSERT_DIE(adpos + size <= elen);
781
782 struct adata *d = ((void *) n) + adpos;
b77ae37d
MM
783 memcpy(d, a->u.ptr, size);
784 a->u.ptr = d;
7c8b7649
MM
785
786 adpos += size;
b77ae37d
MM
787 }
788 }
7c8b7649 789 ASSERT_DIE(adpos == elen);
b77ae37d
MM
790 return n;
791}
792
5d86aefb
MM
793static inline void
794ea_free(ea_list *o)
795{
796 if (o)
797 {
798 ASSERT(!o->next);
799 mb_free(o);
800 }
801}
802
ba5e5940 803static int
258be565 804get_generic_attr(const eattr *a, byte **buf, int buflen UNUSED)
ba5e5940 805{
333ddd4f
OZ
806 switch (a->id)
807 {
808 case EA_GEN_IGP_METRIC:
809 *buf += bsprintf(*buf, "igp_metric");
810 return GA_NAME;
811
812 case EA_MPLS_LABEL:
813 *buf += bsprintf(*buf, "mpls_label");
814 return GA_NAME;
d217ba51 815
333ddd4f
OZ
816 case EA_MPLS_POLICY:
817 *buf += bsprintf(*buf, "mpls_policy");
818 return GA_NAME;
819
820 case EA_MPLS_CLASS:
821 *buf += bsprintf(*buf, "mpls_class");
822 return GA_NAME;
823
824 default:
825 return GA_UNKNOWN;
826 }
ba5e5940
OZ
827}
828
315f23a0 829void
258be565 830ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
315f23a0
OZ
831{
832 byte *bound = buf + bufsize - 32;
833 u32 data = a->u.data;
834 int i;
835
836 for (i = min; i < max; i++)
837 if ((data & (1u << i)) && names[i])
838 {
839 if (buf > bound)
840 {
841 strcpy(buf, " ...");
842 return;
843 }
844
845 buf += bsprintf(buf, " %s", names[i]);
846 data &= ~(1u << i);
847 }
848
849 if (data)
850 bsprintf(buf, " %08x", data);
851
852 return;
853}
854
fdf16eb6 855static inline void
4c553c5a 856opaque_format(const struct adata *ad, byte *buf, uint size)
fdf16eb6
OZ
857{
858 byte *bound = buf + size - 10;
3e236955 859 uint i;
fdf16eb6
OZ
860
861 for(i = 0; i < ad->length; i++)
862 {
863 if (buf > bound)
864 {
865 strcpy(buf, " ...");
866 return;
867 }
868 if (i)
869 *buf++ = ' ';
870
871 buf += bsprintf(buf, "%02x", ad->data[i]);
872 }
873
874 *buf = 0;
875 return;
876}
877
878static inline void
4c553c5a 879ea_show_int_set(struct cli *c, const struct adata *ad, int way, byte *pos, byte *buf, byte *end)
fdf16eb6
OZ
880{
881 int i = int_set_format(ad, way, 0, pos, end - pos);
a52d52fa 882 cli_printf(c, -1012, "\t%s", buf);
fdf16eb6
OZ
883 while (i)
884 {
885 i = int_set_format(ad, way, i, buf, end - buf - 1);
a52d52fa 886 cli_printf(c, -1012, "\t\t%s", buf);
fdf16eb6
OZ
887 }
888}
889
42a0c054 890static inline void
4c553c5a 891ea_show_ec_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end)
42a0c054
OZ
892{
893 int i = ec_set_format(ad, 0, pos, end - pos);
a52d52fa 894 cli_printf(c, -1012, "\t%s", buf);
42a0c054
OZ
895 while (i)
896 {
897 i = ec_set_format(ad, i, buf, end - buf - 1);
a52d52fa 898 cli_printf(c, -1012, "\t\t%s", buf);
42a0c054
OZ
899 }
900}
901
66dbdbd9 902static inline void
4c553c5a 903ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte *end)
66dbdbd9
OZ
904{
905 int i = lc_set_format(ad, 0, pos, end - pos);
906 cli_printf(c, -1012, "\t%s", buf);
907 while (i)
908 {
909 i = lc_set_format(ad, i, buf, end - buf - 1);
910 cli_printf(c, -1012, "\t\t%s", buf);
911 }
912}
913
3ce8c610 914/**
fdf16eb6
OZ
915 * ea_show - print an &eattr to CLI
916 * @c: destination CLI
917 * @e: attribute to be printed
3ce8c610 918 *
fdf16eb6
OZ
919 * This function takes an extended attribute represented by its &eattr
920 * structure and prints it to the CLI according to the type information.
3ce8c610
MM
921 *
922 * If the protocol defining the attribute provides its own
923 * get_attr() hook, it's consulted first.
924 */
3991d84e 925void
258be565 926ea_show(struct cli *c, const eattr *e)
3991d84e
MM
927{
928 struct protocol *p;
929 int status = GA_UNKNOWN;
4c553c5a 930 const struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
fdf16eb6
OZ
931 byte buf[CLI_MSG_SIZE];
932 byte *pos = buf, *end = buf + sizeof(buf);
3991d84e 933
265419a3
MM
934 if (EA_IS_CUSTOM(e->id))
935 {
936 const char *name = ea_custom_name(e->id);
937 if (name)
938 {
939 pos += bsprintf(pos, "%s", name);
940 status = GA_NAME;
941 }
942 else
943 pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
944 }
945 else if (p = class_to_protocol[EA_PROTO(e->id)])
3991d84e 946 {
fdf16eb6 947 pos += bsprintf(pos, "%s.", p->name);
3991d84e 948 if (p->get_attr)
fdf16eb6
OZ
949 status = p->get_attr(e, pos, end - pos);
950 pos += strlen(pos);
3991d84e
MM
951 }
952 else if (EA_PROTO(e->id))
fdf16eb6 953 pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
d217ba51 954 else
fdf16eb6 955 status = get_generic_attr(e, &pos, end - pos);
ba5e5940 956
3991d84e 957 if (status < GA_NAME)
fdf16eb6 958 pos += bsprintf(pos, "%02x", EA_ID(e->id));
3991d84e
MM
959 if (status < GA_FULL)
960 {
fdf16eb6
OZ
961 *pos++ = ':';
962 *pos++ = ' ';
0f685152
MM
963
964 if (e->undef)
965 bsprintf(pos, "undefined");
966 else
3991d84e
MM
967 switch (e->type & EAF_TYPE_MASK)
968 {
969 case EAF_TYPE_INT:
fdf16eb6 970 bsprintf(pos, "%u", e->u.data);
3991d84e
MM
971 break;
972 case EAF_TYPE_OPAQUE:
fdf16eb6 973 opaque_format(ad, pos, end - pos);
3991d84e
MM
974 break;
975 case EAF_TYPE_IP_ADDRESS:
fdf16eb6 976 bsprintf(pos, "%I", *(ip_addr *) ad->data);
3991d84e
MM
977 break;
978 case EAF_TYPE_ROUTER_ID:
fdf16eb6 979 bsprintf(pos, "%R", e->u.data);
3991d84e 980 break;
c6add07f 981 case EAF_TYPE_AS_PATH:
fdf16eb6 982 as_path_format(ad, pos, end - pos);
c6add07f 983 break;
315f23a0
OZ
984 case EAF_TYPE_BITFIELD:
985 bsprintf(pos, "%08x", e->u.data);
986 break;
c6add07f 987 case EAF_TYPE_INT_SET:
fdf16eb6
OZ
988 ea_show_int_set(c, ad, 1, pos, buf, end);
989 return;
42a0c054
OZ
990 case EAF_TYPE_EC_SET:
991 ea_show_ec_set(c, ad, pos, buf, end);
992 return;
66dbdbd9
OZ
993 case EAF_TYPE_LC_SET:
994 ea_show_lc_set(c, ad, pos, buf, end);
995 return;
3991d84e 996 default:
fdf16eb6 997 bsprintf(pos, "<type %02x>", e->type);
3991d84e
MM
998 }
999 }
b28431e5
OZ
1000
1001 if (status != GA_HIDDEN)
1002 cli_printf(c, -1012, "\t%s", buf);
3991d84e
MM
1003}
1004
3ce8c610
MM
1005/**
1006 * ea_dump - dump an extended attribute
1007 * @e: attribute to be dumped
1008 *
1009 * ea_dump() dumps contents of the extended attribute given to
1010 * the debug output.
1011 */
b77ae37d
MM
1012void
1013ea_dump(ea_list *e)
1014{
1015 int i;
1016
1017 if (!e)
1018 {
1019 debug("NONE");
1020 return;
1021 }
1022 while (e)
1023 {
1024 debug("[%c%c%c]",
1025 (e->flags & EALF_SORTED) ? 'S' : 's',
1026 (e->flags & EALF_BISECT) ? 'B' : 'b',
1027 (e->flags & EALF_CACHED) ? 'C' : 'c');
1028 for(i=0; i<e->count; i++)
2326b001 1029 {
b77ae37d
MM
1030 eattr *a = &e->attrs[i];
1031 debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags);
b77ae37d 1032 debug("=%c", "?iO?I?P???S?????" [a->type & EAF_TYPE_MASK]);
63cf5d5d 1033 if (a->originated)
51a183af 1034 debug("o");
b77ae37d
MM
1035 if (a->type & EAF_EMBEDDED)
1036 debug(":%08x", a->u.data);
1037 else
1038 {
1039 int j, len = a->u.ptr->length;
1040 debug("[%d]:", len);
1041 for(j=0; j<len; j++)
1042 debug("%02x", a->u.ptr->data[j]);
1043 }
2326b001 1044 }
b77ae37d
MM
1045 if (e = e->next)
1046 debug(" | ");
2326b001 1047 }
2326b001
MM
1048}
1049
3ce8c610
MM
1050/**
1051 * ea_hash - calculate an &ea_list hash key
1052 * @e: attribute list
1053 *
1054 * ea_hash() takes an extended attribute list and calculated a hopefully
1055 * uniformly distributed hash value from its contents.
1056 */
ae80a2de 1057inline uint
ee76a92a
MM
1058ea_hash(ea_list *e)
1059{
9a74622c
JMM
1060 const u64 mul = 0x68576150f3d6847;
1061 u64 h = 0xafcef24eda8b29;
ee76a92a
MM
1062 int i;
1063
1064 if (e) /* Assuming chain of length 1 */
1065 {
1066 for(i=0; i<e->count; i++)
1067 {
1068 struct eattr *a = &e->attrs[i];
9a74622c 1069 h ^= a->id; h *= mul;
ee76a92a
MM
1070 if (a->type & EAF_EMBEDDED)
1071 h ^= a->u.data;
1072 else
1073 {
4c553c5a 1074 const struct adata *d = a->u.ptr;
9a74622c 1075 h ^= mem_hash(d->data, d->length);
ee76a92a 1076 }
9a74622c 1077 h *= mul;
ee76a92a 1078 }
ee76a92a 1079 }
9a74622c 1080 return (h >> 32) ^ (h & 0xffffffff);
ee76a92a
MM
1081}
1082
3ce8c610
MM
1083/**
1084 * ea_append - concatenate &ea_list's
1085 * @to: destination list (can be %NULL)
1086 * @what: list to be appended (can be %NULL)
1087 *
1088 * This function appends the &ea_list @what at the end of
1089 * &ea_list @to and returns a pointer to the resulting list.
1090 */
ce1da96e
MM
1091ea_list *
1092ea_append(ea_list *to, ea_list *what)
1093{
1094 ea_list *res;
1095
1096 if (!to)
1097 return what;
1098 res = to;
1099 while (to->next)
1100 to = to->next;
1101 to->next = what;
1102 return res;
1103}
1104
b77ae37d
MM
1105/*
1106 * rta's
1107 */
1108
ae80a2de
PT
1109static uint rta_cache_count;
1110static uint rta_cache_size = 32;
1111static uint rta_cache_limit;
1112static uint rta_cache_mask;
ee76a92a
MM
1113static rta **rta_hash_table;
1114
1115static void
1116rta_alloc_hash(void)
1117{
5d86aefb 1118 rta_hash_table = mb_allocz(rta_pool, sizeof(rta *) * rta_cache_size);
ee76a92a
MM
1119 if (rta_cache_size < 32768)
1120 rta_cache_limit = rta_cache_size * 2;
1121 else
1122 rta_cache_limit = ~0;
1123 rta_cache_mask = rta_cache_size - 1;
1124}
1125
ae80a2de 1126static inline uint
ee76a92a
MM
1127rta_hash(rta *a)
1128{
d39d41fb 1129 u64 h;
54ac0bec 1130 mem_hash_init(&h);
d39d41fb 1131#define MIX(f) mem_hash_mix(&h, &(a->f), sizeof(a->f));
eb937358 1132#define BMIX(f) mem_hash_mix_num(&h, a->f);
54ac0bec 1133 MIX(hostentry);
54ac0bec
JMM
1134 MIX(from);
1135 MIX(igp_metric);
eb937358
MM
1136 BMIX(source);
1137 BMIX(scope);
1138 BMIX(dest);
1139 MIX(pref);
d39d41fb 1140#undef MIX
54ac0bec 1141
4e276a89 1142 return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs);
ee76a92a
MM
1143}
1144
2326b001
MM
1145static inline int
1146rta_same(rta *x, rta *y)
1147{
5cff1d5f 1148 return (x->source == y->source &&
2326b001 1149 x->scope == y->scope &&
2326b001 1150 x->dest == y->dest &&
d1e146f2 1151 x->igp_metric == y->igp_metric &&
2326b001 1152 ipa_equal(x->from, y->from) &&
d1e146f2 1153 x->hostentry == y->hostentry &&
4e276a89 1154 nexthop_same(&(x->nh), &(y->nh)) &&
2727bb7c 1155 ea_same(x->eattrs, y->eattrs));
2326b001
MM
1156}
1157
ec5e5d23
JMM
1158static inline slab *
1159rta_slab(rta *a)
1160{
1161 return rta_slab_[a->nh.labels > 2 ? 3 : a->nh.labels];
1162}
1163
2326b001
MM
1164static rta *
1165rta_copy(rta *o)
1166{
ec5e5d23 1167 rta *r = sl_alloc(rta_slab(o));
2326b001 1168
ec5e5d23 1169 memcpy(r, o, rta_size(o));
2326b001 1170 r->uc = 1;
4e276a89 1171 r->nh.next = nexthop_copy(o->nh.next);
2727bb7c 1172 r->eattrs = ea_list_copy(o->eattrs);
2326b001
MM
1173 return r;
1174}
1175
ee76a92a
MM
1176static inline void
1177rta_insert(rta *r)
1178{
ae80a2de 1179 uint h = r->hash_key & rta_cache_mask;
ee76a92a
MM
1180 r->next = rta_hash_table[h];
1181 if (r->next)
1182 r->next->pprev = &r->next;
1183 r->pprev = &rta_hash_table[h];
1184 rta_hash_table[h] = r;
1185}
1186
1187static void
1188rta_rehash(void)
1189{
ae80a2de
PT
1190 uint ohs = rta_cache_size;
1191 uint h;
ee76a92a
MM
1192 rta *r, *n;
1193 rta **oht = rta_hash_table;
1194
1195 rta_cache_size = 2*rta_cache_size;
1196 DBG("Rehashing rta cache from %d to %d entries.\n", ohs, rta_cache_size);
1197 rta_alloc_hash();
1198 for(h=0; h<ohs; h++)
1199 for(r=oht[h]; r; r=n)
1200 {
1201 n = r->next;
1202 rta_insert(r);
1203 }
1204 mb_free(oht);
1205}
1206
3ce8c610
MM
1207/**
1208 * rta_lookup - look up a &rta in attribute cache
2e9b2421 1209 * @o: a un-cached &rta
3ce8c610 1210 *
2e9b2421 1211 * rta_lookup() gets an un-cached &rta structure and returns its cached
3ce8c610
MM
1212 * counterpart. It starts with examining the attribute cache to see whether
1213 * there exists a matching entry. If such an entry exists, it's returned and
1214 * its use count is incremented, else a new entry is created with use count
1215 * set to 1.
1216 *
1217 * The extended attribute lists attached to the &rta are automatically
1218 * converted to the normalized form.
1219 */
2326b001
MM
1220rta *
1221rta_lookup(rta *o)
1222{
1223 rta *r;
ae80a2de 1224 uint h;
2326b001 1225
eb937358 1226 ASSERT(!o->cached);
2727bb7c 1227 if (o->eattrs)
13c0be19 1228 ea_normalize(o->eattrs);
b77ae37d 1229
ee76a92a
MM
1230 h = rta_hash(o);
1231 for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next)
1232 if (r->hash_key == h && rta_same(r, o))
2326b001 1233 return rta_clone(r);
b77ae37d 1234
2326b001 1235 r = rta_copy(o);
ee76a92a 1236 r->hash_key = h;
eb937358 1237 r->cached = 1;
cfe34a31 1238 rt_lock_hostentry(r->hostentry);
ee76a92a
MM
1239 rta_insert(r);
1240
1241 if (++rta_cache_count > rta_cache_limit)
1242 rta_rehash();
1243
2326b001
MM
1244 return r;
1245}
1246
1247void
b77ae37d 1248rta__free(rta *a)
2326b001 1249{
eb937358 1250 ASSERT(rta_cache_count && a->cached);
ee76a92a 1251 rta_cache_count--;
5d86aefb
MM
1252 *a->pprev = a->next;
1253 if (a->next)
1254 a->next->pprev = a->pprev;
cfe34a31 1255 rt_unlock_hostentry(a->hostentry);
4e276a89
JMM
1256 if (a->nh.next)
1257 nexthop_free(a->nh.next);
5d86aefb 1258 ea_free(a->eattrs);
eb937358 1259 a->cached = 0;
ebd807c0 1260 sl_free(a);
2326b001
MM
1261}
1262
8d9eef17
OZ
1263rta *
1264rta_do_cow(rta *o, linpool *lp)
1265{
ec5e5d23
JMM
1266 rta *r = lp_alloc(lp, rta_size(o));
1267 memcpy(r, o, rta_size(o));
f2010f9c
JMM
1268 for (struct nexthop **nhn = &(r->nh.next), *nho = o->nh.next; nho; nho = nho->next)
1269 {
1270 *nhn = lp_alloc(lp, nexthop_size(nho));
1271 memcpy(*nhn, nho, nexthop_size(nho));
1272 nhn = &((*nhn)->next);
1273 }
eb937358 1274 r->cached = 0;
8d9eef17
OZ
1275 r->uc = 0;
1276 return r;
1277}
1278
3ce8c610
MM
1279/**
1280 * rta_dump - dump route attributes
1281 * @a: attribute structure to dump
1282 *
1283 * This function takes a &rta and dumps its contents to the debug output.
1284 */
2326b001 1285void
66e53309 1286rta_dump(rta *a)
2326b001 1287{
3660f19d 1288 static char *rts[] = { "", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
beaf86e1 1289 "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
98ac6176 1290 "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1",
977b82fb
IP
1291 "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL",
1292 "RTS_RPKI", "RTS_PERF", "RTS_AGGREGATED", };
66e53309
MM
1293 static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
1294
5cff1d5f
MM
1295 debug("pref=%d uc=%d %s %s%s h=%04x",
1296 a->pref, a->uc, rts[a->source], ip_scope_text(a->scope),
ee76a92a 1297 rtd[a->dest], a->hash_key);
eb937358 1298 if (!a->cached)
04925e90 1299 debug(" !CACHED");
962ba482 1300 debug(" <-%I", a->from);
4e276a89
JMM
1301 if (a->dest == RTD_UNICAST)
1302 for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
1303 {
1304 if (ipa_nonzero(nh->gw)) debug(" ->%I", nh->gw);
ec5e5d23
JMM
1305 if (nh->labels) debug(" L %d", nh->label[0]);
1306 for (int i=1; i<nh->labels; i++)
1307 debug("/%d", nh->label[i]);
4e276a89
JMM
1308 debug(" [%s]", nh->iface ? nh->iface->name : "???");
1309 }
2727bb7c 1310 if (a->eattrs)
b77ae37d
MM
1311 {
1312 debug(" EA: ");
2727bb7c 1313 ea_dump(a->eattrs);
b77ae37d 1314 }
2326b001
MM
1315}
1316
3ce8c610
MM
1317/**
1318 * rta_dump_all - dump attribute cache
1319 *
1320 * This function dumps the whole contents of route attribute cache
1321 * to the debug output.
1322 */
2326b001
MM
1323void
1324rta_dump_all(void)
1325{
66e53309 1326 rta *a;
ae80a2de 1327 uint h;
ee76a92a
MM
1328
1329 debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
1330 for(h=0; h<rta_cache_size; h++)
1331 for(a=rta_hash_table[h]; a; a=a->next)
1332 {
1333 debug("%p ", a);
1334 rta_dump(a);
1335 debug("\n");
1336 }
66e53309 1337 debug("\n");
2326b001
MM
1338}
1339
730f2e2c 1340void
13c0be19 1341rta_show(struct cli *c, rta *a)
730f2e2c 1342{
69b2f63d 1343 cli_printf(c, -1008, "\tType: %s %s", rta_src_names[a->source], ip_scope_text(a->scope));
13c0be19
JMM
1344
1345 for(ea_list *eal = a->eattrs; eal; eal=eal->next)
1346 for(int i=0; i<eal->count; i++)
fdf16eb6 1347 ea_show(c, &eal->attrs[i]);
730f2e2c
MM
1348}
1349
3ce8c610
MM
1350/**
1351 * rta_init - initialize route attribute cache
1352 *
1353 * This function is called during initialization of the routing
1354 * table module to set up the internals of the attribute cache.
1355 */
2326b001
MM
1356void
1357rta_init(void)
1358{
ed68a5c6 1359 rta_pool = rp_new(&root_pool, "Attributes");
ec5e5d23
JMM
1360
1361 rta_slab_[0] = sl_new(rta_pool, sizeof(rta));
1362 rta_slab_[1] = sl_new(rta_pool, sizeof(rta) + sizeof(u32));
1363 rta_slab_[2] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*2);
d14f8c3c 1364 rta_slab_[3] = sl_new(rta_pool, sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK);
ec5e5d23
JMM
1365
1366 nexthop_slab_[0] = sl_new(rta_pool, sizeof(struct nexthop));
1367 nexthop_slab_[1] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32));
1368 nexthop_slab_[2] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*2);
d14f8c3c 1369 nexthop_slab_[3] = sl_new(rta_pool, sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK);
ec5e5d23 1370
ee76a92a 1371 rta_alloc_hash();
094d2bdb 1372 rte_src_init();
2326b001 1373}
3ce8c610
MM
1374
1375/*
1376 * Documentation for functions declared inline in route.h
1377 */
1378#if 0
1379
1380/**
1381 * rta_clone - clone route attributes
1382 * @r: a &rta to be cloned
1383 *
1384 * rta_clone() takes a cached &rta and returns its identical cached
1385 * copy. Currently it works by just returning the original &rta with
1386 * its use count incremented.
1387 */
1388static inline rta *rta_clone(rta *r)
1389{ DUMMY; }
1390
1391/**
1392 * rta_free - free route attributes
1393 * @r: a &rta to be freed
1394 *
1395 * If you stop using a &rta (for example when deleting a route which uses
1396 * it), you need to call rta_free() to notify the attribute cache the
1397 * attribute is no longer in use and can be freed if you were the last
1398 * user (which rta_free() tests by inspecting the use count).
1399 */
1400static inline void rta_free(rta *r)
1401{ DUMMY; }
1402
1403#endif