]> git.ipfire.org Git - thirdparty/bird.git/blob - nest/rt-attr.c
Merge commit 'origin/bfd'
[thirdparty/bird.git] / nest / rt-attr.c
1 /*
2 * BIRD -- Route Attribute Cache
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
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
24 * in the &ea_list chain and in such case the first occurrence overrides
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 *
36 * There exist two variants of &rta's -- cached and un-cached ones. Un-cached
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
47 #include "nest/bird.h"
48 #include "nest/route.h"
49 #include "nest/protocol.h"
50 #include "nest/iface.h"
51 #include "nest/cli.h"
52 #include "nest/attrs.h"
53 #include "lib/alloca.h"
54 #include "lib/resource.h"
55 #include "lib/string.h"
56
57 pool *rta_pool;
58
59 static slab *rta_slab;
60 static slab *mpnh_slab;
61
62 struct protocol *attr_class_to_protocol[EAP_MAX];
63
64 static inline unsigned int
65 mpnh_hash(struct mpnh *x)
66 {
67 unsigned int h = 0;
68 for (; x; x = x->next)
69 h ^= ipa_hash(x->gw);
70
71 return h;
72 }
73
74 int
75 mpnh__same(struct mpnh *x, struct mpnh *y)
76 {
77 for (; x && y; x = x->next, y = y->next)
78 if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight))
79 return 0;
80
81 return x == y;
82 }
83
84 static struct mpnh *
85 mpnh_copy(struct mpnh *o)
86 {
87 struct mpnh *first = NULL;
88 struct mpnh **last = &first;
89
90 for (; o; o = o->next)
91 {
92 struct mpnh *n = sl_alloc(mpnh_slab);
93 n->gw = o->gw;
94 n->iface = o->iface;
95 n->next = NULL;
96 n->weight = o->weight;
97
98 *last = n;
99 last = &(n->next);
100 }
101
102 return first;
103 }
104
105 static void
106 mpnh_free(struct mpnh *o)
107 {
108 struct mpnh *n;
109
110 while (o)
111 {
112 n = o->next;
113 sl_free(mpnh_slab, o);
114 o = n;
115 }
116 }
117
118
119 /*
120 * Extended Attributes
121 */
122
123 static inline eattr *
124 ea__find(ea_list *e, unsigned id)
125 {
126 eattr *a;
127 int l, r, m;
128
129 while (e)
130 {
131 if (e->flags & EALF_BISECT)
132 {
133 l = 0;
134 r = e->count - 1;
135 while (l <= r)
136 {
137 m = (l+r) / 2;
138 a = &e->attrs[m];
139 if (a->id == id)
140 return a;
141 else if (a->id < id)
142 l = m+1;
143 else
144 r = m-1;
145 }
146 }
147 else
148 for(m=0; m<e->count; m++)
149 if (e->attrs[m].id == id)
150 return &e->attrs[m];
151 e = e->next;
152 }
153 return NULL;
154 }
155
156 /**
157 * ea_find - find an extended attribute
158 * @e: attribute list to search in
159 * @id: attribute ID to search for
160 *
161 * Given an extended attribute list, ea_find() searches for a first
162 * occurrence of an attribute with specified ID, returning either a pointer
163 * to its &eattr structure or %NULL if no such attribute exists.
164 */
165 eattr *
166 ea_find(ea_list *e, unsigned id)
167 {
168 eattr *a = ea__find(e, id & EA_CODE_MASK);
169
170 if (a && (a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF &&
171 !(id & EA_ALLOW_UNDEF))
172 return NULL;
173 return a;
174 }
175
176 /**
177 * ea_get_int - fetch an integer attribute
178 * @e: attribute list
179 * @id: attribute ID
180 * @def: default value
181 *
182 * This function is a shortcut for retrieving a value of an integer attribute
183 * by calling ea_find() to find the attribute, extracting its value or returning
184 * a provided default if no such attribute is present.
185 */
186 int
187 ea_get_int(ea_list *e, unsigned id, int def)
188 {
189 eattr *a = ea_find(e, id);
190 if (!a)
191 return def;
192 return a->u.data;
193 }
194
195 static inline void
196 ea_do_sort(ea_list *e)
197 {
198 unsigned n = e->count;
199 eattr *a = e->attrs;
200 eattr *b = alloca(n * sizeof(eattr));
201 unsigned s, ss;
202
203 /* We need to use a stable sorting algorithm, hence mergesort */
204 do
205 {
206 s = ss = 0;
207 while (s < n)
208 {
209 eattr *p, *q, *lo, *hi;
210 p = b;
211 ss = s;
212 *p++ = a[s++];
213 while (s < n && p[-1].id <= a[s].id)
214 *p++ = a[s++];
215 if (s < n)
216 {
217 q = p;
218 *p++ = a[s++];
219 while (s < n && p[-1].id <= a[s].id)
220 *p++ = a[s++];
221 lo = b;
222 hi = q;
223 s = ss;
224 while (lo < q && hi < p)
225 if (lo->id <= hi->id)
226 a[s++] = *lo++;
227 else
228 a[s++] = *hi++;
229 while (lo < q)
230 a[s++] = *lo++;
231 while (hi < p)
232 a[s++] = *hi++;
233 }
234 }
235 }
236 while (ss);
237 }
238
239 static inline void
240 ea_do_prune(ea_list *e)
241 {
242 eattr *s, *d, *l, *s0;
243 int i = 0;
244
245 /* Discard duplicates and undefs. Do you remember sorting was stable? */
246 s = d = e->attrs;
247 l = e->attrs + e->count;
248 while (s < l)
249 {
250 s0 = s++;
251 while (s < l && s->id == s[-1].id)
252 s++;
253 /* s0 is the most recent version, s[-1] the oldest one */
254 if ((s0->type & EAF_TYPE_MASK) != EAF_TYPE_UNDEF)
255 {
256 *d = *s0;
257 d->type = (d->type & ~EAF_ORIGINATED) | (s[-1].type & EAF_ORIGINATED);
258 d++;
259 i++;
260 }
261 }
262 e->count = i;
263 }
264
265 /**
266 * ea_sort - sort an attribute list
267 * @e: list to be sorted
268 *
269 * This function takes a &ea_list chain and sorts the attributes
270 * within each of its entries.
271 *
272 * If an attribute occurs multiple times in a single &ea_list,
273 * ea_sort() leaves only the first (the only significant) occurrence.
274 */
275 void
276 ea_sort(ea_list *e)
277 {
278 while (e)
279 {
280 if (!(e->flags & EALF_SORTED))
281 {
282 ea_do_sort(e);
283 ea_do_prune(e);
284 e->flags |= EALF_SORTED;
285 }
286 if (e->count > 5)
287 e->flags |= EALF_BISECT;
288 e = e->next;
289 }
290 }
291
292 /**
293 * ea_scan - estimate attribute list size
294 * @e: attribute list
295 *
296 * This function calculates an upper bound of the size of
297 * a given &ea_list after merging with ea_merge().
298 */
299 unsigned
300 ea_scan(ea_list *e)
301 {
302 unsigned cnt = 0;
303
304 while (e)
305 {
306 cnt += e->count;
307 e = e->next;
308 }
309 return sizeof(ea_list) + sizeof(eattr)*cnt;
310 }
311
312 /**
313 * ea_merge - merge segments of an attribute list
314 * @e: attribute list
315 * @t: buffer to store the result to
316 *
317 * This function takes a possibly multi-segment attribute list
318 * and merges all of its segments to one.
319 *
320 * The primary use of this function is for &ea_list normalization:
321 * first call ea_scan() to determine how much memory will the result
322 * take, then allocate a buffer (usually using alloca()), merge the
323 * segments with ea_merge() and finally sort and prune the result
324 * by calling ea_sort().
325 */
326 void
327 ea_merge(ea_list *e, ea_list *t)
328 {
329 eattr *d = t->attrs;
330
331 t->flags = 0;
332 t->count = 0;
333 t->next = NULL;
334 while (e)
335 {
336 memcpy(d, e->attrs, sizeof(eattr)*e->count);
337 t->count += e->count;
338 d += e->count;
339 e = e->next;
340 }
341 }
342
343 /**
344 * ea_same - compare two &ea_list's
345 * @x: attribute list
346 * @y: attribute list
347 *
348 * ea_same() compares two normalized attribute lists @x and @y and returns
349 * 1 if they contain the same attributes, 0 otherwise.
350 */
351 int
352 ea_same(ea_list *x, ea_list *y)
353 {
354 int c;
355
356 if (!x || !y)
357 return x == y;
358 ASSERT(!x->next && !y->next);
359 if (x->count != y->count)
360 return 0;
361 for(c=0; c<x->count; c++)
362 {
363 eattr *a = &x->attrs[c];
364 eattr *b = &y->attrs[c];
365
366 if (a->id != b->id ||
367 a->flags != b->flags ||
368 a->type != b->type ||
369 ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr)))
370 return 0;
371 }
372 return 1;
373 }
374
375 static inline ea_list *
376 ea_list_copy(ea_list *o)
377 {
378 ea_list *n;
379 unsigned i, len;
380
381 if (!o)
382 return NULL;
383 ASSERT(!o->next);
384 len = sizeof(ea_list) + sizeof(eattr) * o->count;
385 n = mb_alloc(rta_pool, len);
386 memcpy(n, o, len);
387 n->flags |= EALF_CACHED;
388 for(i=0; i<o->count; i++)
389 {
390 eattr *a = &n->attrs[i];
391 if (!(a->type & EAF_EMBEDDED))
392 {
393 unsigned size = sizeof(struct adata) + a->u.ptr->length;
394 struct adata *d = mb_alloc(rta_pool, size);
395 memcpy(d, a->u.ptr, size);
396 a->u.ptr = d;
397 }
398 }
399 return n;
400 }
401
402 static inline void
403 ea_free(ea_list *o)
404 {
405 int i;
406
407 if (o)
408 {
409 ASSERT(!o->next);
410 for(i=0; i<o->count; i++)
411 {
412 eattr *a = &o->attrs[i];
413 if (!(a->type & EAF_EMBEDDED))
414 mb_free(a->u.ptr);
415 }
416 mb_free(o);
417 }
418 }
419
420 static int
421 get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
422 {
423 if (a->id == EA_GEN_IGP_METRIC)
424 {
425 *buf += bsprintf(*buf, "igp_metric");
426 return GA_NAME;
427 }
428
429 return GA_UNKNOWN;
430 }
431
432 static inline void
433 opaque_format(struct adata *ad, byte *buf, unsigned int size)
434 {
435 byte *bound = buf + size - 10;
436 int i;
437
438 for(i = 0; i < ad->length; i++)
439 {
440 if (buf > bound)
441 {
442 strcpy(buf, " ...");
443 return;
444 }
445 if (i)
446 *buf++ = ' ';
447
448 buf += bsprintf(buf, "%02x", ad->data[i]);
449 }
450
451 *buf = 0;
452 return;
453 }
454
455 static inline void
456 ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, byte *end)
457 {
458 int i = int_set_format(ad, way, 0, pos, end - pos);
459 cli_printf(c, -1012, "\t%s", buf);
460 while (i)
461 {
462 i = int_set_format(ad, way, i, buf, end - buf - 1);
463 cli_printf(c, -1012, "\t\t%s", buf);
464 }
465 }
466
467 static inline void
468 ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
469 {
470 int i = ec_set_format(ad, 0, pos, end - pos);
471 cli_printf(c, -1012, "\t%s", buf);
472 while (i)
473 {
474 i = ec_set_format(ad, i, buf, end - buf - 1);
475 cli_printf(c, -1012, "\t\t%s", buf);
476 }
477 }
478
479 /**
480 * ea_show - print an &eattr to CLI
481 * @c: destination CLI
482 * @e: attribute to be printed
483 *
484 * This function takes an extended attribute represented by its &eattr
485 * structure and prints it to the CLI according to the type information.
486 *
487 * If the protocol defining the attribute provides its own
488 * get_attr() hook, it's consulted first.
489 */
490 void
491 ea_show(struct cli *c, eattr *e)
492 {
493 struct protocol *p;
494 int status = GA_UNKNOWN;
495 struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
496 byte buf[CLI_MSG_SIZE];
497 byte *pos = buf, *end = buf + sizeof(buf);
498
499 if (p = attr_class_to_protocol[EA_PROTO(e->id)])
500 {
501 pos += bsprintf(pos, "%s.", p->name);
502 if (p->get_attr)
503 status = p->get_attr(e, pos, end - pos);
504 pos += strlen(pos);
505 }
506 else if (EA_PROTO(e->id))
507 pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
508 else
509 status = get_generic_attr(e, &pos, end - pos);
510
511 if (status < GA_NAME)
512 pos += bsprintf(pos, "%02x", EA_ID(e->id));
513 if (status < GA_FULL)
514 {
515 *pos++ = ':';
516 *pos++ = ' ';
517 switch (e->type & EAF_TYPE_MASK)
518 {
519 case EAF_TYPE_INT:
520 bsprintf(pos, "%u", e->u.data);
521 break;
522 case EAF_TYPE_OPAQUE:
523 opaque_format(ad, pos, end - pos);
524 break;
525 case EAF_TYPE_IP_ADDRESS:
526 bsprintf(pos, "%I", *(ip_addr *) ad->data);
527 break;
528 case EAF_TYPE_ROUTER_ID:
529 bsprintf(pos, "%R", e->u.data);
530 break;
531 case EAF_TYPE_AS_PATH:
532 as_path_format(ad, pos, end - pos);
533 break;
534 case EAF_TYPE_INT_SET:
535 ea_show_int_set(c, ad, 1, pos, buf, end);
536 return;
537 case EAF_TYPE_EC_SET:
538 ea_show_ec_set(c, ad, pos, buf, end);
539 return;
540 case EAF_TYPE_UNDEF:
541 default:
542 bsprintf(pos, "<type %02x>", e->type);
543 }
544 }
545 cli_printf(c, -1012, "\t%s", buf);
546 }
547
548 /**
549 * ea_dump - dump an extended attribute
550 * @e: attribute to be dumped
551 *
552 * ea_dump() dumps contents of the extended attribute given to
553 * the debug output.
554 */
555 void
556 ea_dump(ea_list *e)
557 {
558 int i;
559
560 if (!e)
561 {
562 debug("NONE");
563 return;
564 }
565 while (e)
566 {
567 debug("[%c%c%c]",
568 (e->flags & EALF_SORTED) ? 'S' : 's',
569 (e->flags & EALF_BISECT) ? 'B' : 'b',
570 (e->flags & EALF_CACHED) ? 'C' : 'c');
571 for(i=0; i<e->count; i++)
572 {
573 eattr *a = &e->attrs[i];
574 debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags);
575 if (a->type & EAF_TEMP)
576 debug("T");
577 debug("=%c", "?iO?I?P???S?????" [a->type & EAF_TYPE_MASK]);
578 if (a->type & EAF_ORIGINATED)
579 debug("o");
580 if (a->type & EAF_EMBEDDED)
581 debug(":%08x", a->u.data);
582 else
583 {
584 int j, len = a->u.ptr->length;
585 debug("[%d]:", len);
586 for(j=0; j<len; j++)
587 debug("%02x", a->u.ptr->data[j]);
588 }
589 }
590 if (e = e->next)
591 debug(" | ");
592 }
593 }
594
595 /**
596 * ea_hash - calculate an &ea_list hash key
597 * @e: attribute list
598 *
599 * ea_hash() takes an extended attribute list and calculated a hopefully
600 * uniformly distributed hash value from its contents.
601 */
602 inline unsigned int
603 ea_hash(ea_list *e)
604 {
605 u32 h = 0;
606 int i;
607
608 if (e) /* Assuming chain of length 1 */
609 {
610 for(i=0; i<e->count; i++)
611 {
612 struct eattr *a = &e->attrs[i];
613 h ^= a->id;
614 if (a->type & EAF_EMBEDDED)
615 h ^= a->u.data;
616 else
617 {
618 struct adata *d = a->u.ptr;
619 int size = d->length;
620 byte *z = d->data;
621 while (size >= 4)
622 {
623 h ^= *(u32 *)z;
624 z += 4;
625 size -= 4;
626 }
627 while (size--)
628 h = (h >> 24) ^ (h << 8) ^ *z++;
629 }
630 }
631 h ^= h >> 16;
632 h ^= h >> 6;
633 h &= 0xffff;
634 }
635 return h;
636 }
637
638 /**
639 * ea_append - concatenate &ea_list's
640 * @to: destination list (can be %NULL)
641 * @what: list to be appended (can be %NULL)
642 *
643 * This function appends the &ea_list @what at the end of
644 * &ea_list @to and returns a pointer to the resulting list.
645 */
646 ea_list *
647 ea_append(ea_list *to, ea_list *what)
648 {
649 ea_list *res;
650
651 if (!to)
652 return what;
653 res = to;
654 while (to->next)
655 to = to->next;
656 to->next = what;
657 return res;
658 }
659
660 /*
661 * rta's
662 */
663
664 static unsigned int rta_cache_count;
665 static unsigned int rta_cache_size = 32;
666 static unsigned int rta_cache_limit;
667 static unsigned int rta_cache_mask;
668 static rta **rta_hash_table;
669
670 static void
671 rta_alloc_hash(void)
672 {
673 rta_hash_table = mb_allocz(rta_pool, sizeof(rta *) * rta_cache_size);
674 if (rta_cache_size < 32768)
675 rta_cache_limit = rta_cache_size * 2;
676 else
677 rta_cache_limit = ~0;
678 rta_cache_mask = rta_cache_size - 1;
679 }
680
681 static inline unsigned int
682 rta_hash(rta *a)
683 {
684 return (a->proto->hash_key ^ ipa_hash(a->gw) ^
685 mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
686 }
687
688 static inline int
689 rta_same(rta *x, rta *y)
690 {
691 return (x->proto == y->proto &&
692 x->source == y->source &&
693 x->scope == y->scope &&
694 x->cast == y->cast &&
695 x->dest == y->dest &&
696 x->flags == y->flags &&
697 x->igp_metric == y->igp_metric &&
698 ipa_equal(x->gw, y->gw) &&
699 ipa_equal(x->from, y->from) &&
700 x->iface == y->iface &&
701 x->hostentry == y->hostentry &&
702 mpnh_same(x->nexthops, y->nexthops) &&
703 ea_same(x->eattrs, y->eattrs));
704 }
705
706 static rta *
707 rta_copy(rta *o)
708 {
709 rta *r = sl_alloc(rta_slab);
710
711 memcpy(r, o, sizeof(rta));
712 r->uc = 1;
713 r->nexthops = mpnh_copy(o->nexthops);
714 r->eattrs = ea_list_copy(o->eattrs);
715 return r;
716 }
717
718 static inline void
719 rta_insert(rta *r)
720 {
721 unsigned int h = r->hash_key & rta_cache_mask;
722 r->next = rta_hash_table[h];
723 if (r->next)
724 r->next->pprev = &r->next;
725 r->pprev = &rta_hash_table[h];
726 rta_hash_table[h] = r;
727 }
728
729 static void
730 rta_rehash(void)
731 {
732 unsigned int ohs = rta_cache_size;
733 unsigned int h;
734 rta *r, *n;
735 rta **oht = rta_hash_table;
736
737 rta_cache_size = 2*rta_cache_size;
738 DBG("Rehashing rta cache from %d to %d entries.\n", ohs, rta_cache_size);
739 rta_alloc_hash();
740 for(h=0; h<ohs; h++)
741 for(r=oht[h]; r; r=n)
742 {
743 n = r->next;
744 rta_insert(r);
745 }
746 mb_free(oht);
747 }
748
749 /**
750 * rta_lookup - look up a &rta in attribute cache
751 * @o: a un-cached &rta
752 *
753 * rta_lookup() gets an un-cached &rta structure and returns its cached
754 * counterpart. It starts with examining the attribute cache to see whether
755 * there exists a matching entry. If such an entry exists, it's returned and
756 * its use count is incremented, else a new entry is created with use count
757 * set to 1.
758 *
759 * The extended attribute lists attached to the &rta are automatically
760 * converted to the normalized form.
761 */
762 rta *
763 rta_lookup(rta *o)
764 {
765 rta *r;
766 unsigned int h;
767
768 ASSERT(!(o->aflags & RTAF_CACHED));
769 if (o->eattrs)
770 {
771 if (o->eattrs->next) /* Multiple ea_list's, need to merge them */
772 {
773 ea_list *ml = alloca(ea_scan(o->eattrs));
774 ea_merge(o->eattrs, ml);
775 o->eattrs = ml;
776 }
777 ea_sort(o->eattrs);
778 }
779
780 h = rta_hash(o);
781 for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next)
782 if (r->hash_key == h && rta_same(r, o))
783 return rta_clone(r);
784
785 r = rta_copy(o);
786 r->hash_key = h;
787 r->aflags = RTAF_CACHED;
788 rt_lock_hostentry(r->hostentry);
789 rta_insert(r);
790
791 if (++rta_cache_count > rta_cache_limit)
792 rta_rehash();
793
794 return r;
795 }
796
797 void
798 rta__free(rta *a)
799 {
800 ASSERT(rta_cache_count && (a->aflags & RTAF_CACHED));
801 rta_cache_count--;
802 *a->pprev = a->next;
803 if (a->next)
804 a->next->pprev = a->pprev;
805 a->aflags = 0; /* Poison the entry */
806 rt_unlock_hostentry(a->hostentry);
807 mpnh_free(a->nexthops);
808 ea_free(a->eattrs);
809 sl_free(rta_slab, a);
810 }
811
812 /**
813 * rta_dump - dump route attributes
814 * @a: attribute structure to dump
815 *
816 * This function takes a &rta and dumps its contents to the debug output.
817 */
818 void
819 rta_dump(rta *a)
820 {
821 static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
822 "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
823 "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1",
824 "RTS_OSPF_EXT2", "RTS_BGP" };
825 static char *rtc[] = { "", " BC", " MC", " AC" };
826 static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
827
828 debug("p=%s uc=%d %s %s%s%s h=%04x",
829 a->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
830 rtd[a->dest], a->hash_key);
831 if (!(a->aflags & RTAF_CACHED))
832 debug(" !CACHED");
833 debug(" <-%I", a->from);
834 if (a->dest == RTD_ROUTER)
835 debug(" ->%I", a->gw);
836 if (a->dest == RTD_DEVICE || a->dest == RTD_ROUTER)
837 debug(" [%s]", a->iface ? a->iface->name : "???" );
838 if (a->eattrs)
839 {
840 debug(" EA: ");
841 ea_dump(a->eattrs);
842 }
843 }
844
845 /**
846 * rta_dump_all - dump attribute cache
847 *
848 * This function dumps the whole contents of route attribute cache
849 * to the debug output.
850 */
851 void
852 rta_dump_all(void)
853 {
854 rta *a;
855 unsigned int h;
856
857 debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
858 for(h=0; h<rta_cache_size; h++)
859 for(a=rta_hash_table[h]; a; a=a->next)
860 {
861 debug("%p ", a);
862 rta_dump(a);
863 debug("\n");
864 }
865 debug("\n");
866 }
867
868 void
869 rta_show(struct cli *c, rta *a, ea_list *eal)
870 {
871 static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
872 "RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" };
873 static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
874 int i;
875
876 cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope));
877 if (!eal)
878 eal = a->eattrs;
879 for(; eal; eal=eal->next)
880 for(i=0; i<eal->count; i++)
881 ea_show(c, &eal->attrs[i]);
882 }
883
884 /**
885 * rta_init - initialize route attribute cache
886 *
887 * This function is called during initialization of the routing
888 * table module to set up the internals of the attribute cache.
889 */
890 void
891 rta_init(void)
892 {
893 rta_pool = rp_new(&root_pool, "Attributes");
894 rta_slab = sl_new(rta_pool, sizeof(rta));
895 mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh));
896 rta_alloc_hash();
897 }
898
899 /*
900 * Documentation for functions declared inline in route.h
901 */
902 #if 0
903
904 /**
905 * rta_clone - clone route attributes
906 * @r: a &rta to be cloned
907 *
908 * rta_clone() takes a cached &rta and returns its identical cached
909 * copy. Currently it works by just returning the original &rta with
910 * its use count incremented.
911 */
912 static inline rta *rta_clone(rta *r)
913 { DUMMY; }
914
915 /**
916 * rta_free - free route attributes
917 * @r: a &rta to be freed
918 *
919 * If you stop using a &rta (for example when deleting a route which uses
920 * it), you need to call rta_free() to notify the attribute cache the
921 * attribute is no longer in use and can be freed if you were the last
922 * user (which rta_free() tests by inspecting the use count).
923 */
924 static inline void rta_free(rta *r)
925 { DUMMY; }
926
927 #endif