]> git.ipfire.org Git - thirdparty/bird.git/blob - nest/rt-attr.c
Prints full community lists during 'show route all'.
[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 :
370 (a->u.ptr->length != b->u.ptr->length || memcmp(a->u.ptr->data, b->u.ptr->data, a->u.ptr->length))))
371 return 0;
372 }
373 return 1;
374 }
375
376 static inline ea_list *
377 ea_list_copy(ea_list *o)
378 {
379 ea_list *n;
380 unsigned i, len;
381
382 if (!o)
383 return NULL;
384 ASSERT(!o->next);
385 len = sizeof(ea_list) + sizeof(eattr) * o->count;
386 n = mb_alloc(rta_pool, len);
387 memcpy(n, o, len);
388 n->flags |= EALF_CACHED;
389 for(i=0; i<o->count; i++)
390 {
391 eattr *a = &n->attrs[i];
392 if (!(a->type & EAF_EMBEDDED))
393 {
394 unsigned size = sizeof(struct adata) + a->u.ptr->length;
395 struct adata *d = mb_alloc(rta_pool, size);
396 memcpy(d, a->u.ptr, size);
397 a->u.ptr = d;
398 }
399 }
400 return n;
401 }
402
403 static inline void
404 ea_free(ea_list *o)
405 {
406 int i;
407
408 if (o)
409 {
410 ASSERT(!o->next);
411 for(i=0; i<o->count; i++)
412 {
413 eattr *a = &o->attrs[i];
414 if (!(a->type & EAF_EMBEDDED))
415 mb_free(a->u.ptr);
416 }
417 mb_free(o);
418 }
419 }
420
421 static int
422 get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
423 {
424 if (a->id == EA_GEN_IGP_METRIC)
425 {
426 *buf += bsprintf(*buf, "igp_metric");
427 return GA_NAME;
428 }
429
430 return GA_UNKNOWN;
431 }
432
433 static inline void
434 opaque_format(struct adata *ad, byte *buf, unsigned int size)
435 {
436 byte *bound = buf + size - 10;
437 int i;
438
439 for(i = 0; i < ad->length; i++)
440 {
441 if (buf > bound)
442 {
443 strcpy(buf, " ...");
444 return;
445 }
446 if (i)
447 *buf++ = ' ';
448
449 buf += bsprintf(buf, "%02x", ad->data[i]);
450 }
451
452 *buf = 0;
453 return;
454 }
455
456 static inline void
457 ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf, byte *end)
458 {
459 int i = int_set_format(ad, way, 0, pos, end - pos);
460 cli_printf(c, -1012, "%s", buf);
461 while (i)
462 {
463 i = int_set_format(ad, way, i, buf, end - buf - 1);
464 cli_printf(c, -1012, "\t%s", buf);
465 }
466 }
467
468 /**
469 * ea_show - print an &eattr to CLI
470 * @c: destination CLI
471 * @e: attribute to be printed
472 *
473 * This function takes an extended attribute represented by its &eattr
474 * structure and prints it to the CLI according to the type information.
475 *
476 * If the protocol defining the attribute provides its own
477 * get_attr() hook, it's consulted first.
478 */
479 void
480 ea_show(struct cli *c, eattr *e)
481 {
482 struct protocol *p;
483 int status = GA_UNKNOWN;
484 struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr;
485 byte buf[CLI_MSG_SIZE];
486 byte *pos = buf, *end = buf + sizeof(buf);
487
488 if (p = attr_class_to_protocol[EA_PROTO(e->id)])
489 {
490 pos += bsprintf(pos, "%s.", p->name);
491 if (p->get_attr)
492 status = p->get_attr(e, pos, end - pos);
493 pos += strlen(pos);
494 }
495 else if (EA_PROTO(e->id))
496 pos += bsprintf(pos, "%02x.", EA_PROTO(e->id));
497 else
498 status = get_generic_attr(e, &pos, end - pos);
499
500 if (status < GA_NAME)
501 pos += bsprintf(pos, "%02x", EA_ID(e->id));
502 if (status < GA_FULL)
503 {
504 *pos++ = ':';
505 *pos++ = ' ';
506 switch (e->type & EAF_TYPE_MASK)
507 {
508 case EAF_TYPE_INT:
509 bsprintf(pos, "%u", e->u.data);
510 break;
511 case EAF_TYPE_OPAQUE:
512 opaque_format(ad, pos, end - pos);
513 break;
514 case EAF_TYPE_IP_ADDRESS:
515 bsprintf(pos, "%I", *(ip_addr *) ad->data);
516 break;
517 case EAF_TYPE_ROUTER_ID:
518 bsprintf(pos, "%R", e->u.data);
519 break;
520 case EAF_TYPE_AS_PATH:
521 as_path_format(ad, pos, end - pos);
522 break;
523 case EAF_TYPE_INT_SET:
524 ea_show_int_set(c, ad, 1, pos, buf, end);
525 return;
526 case EAF_TYPE_UNDEF:
527 default:
528 bsprintf(pos, "<type %02x>", e->type);
529 }
530 }
531 cli_printf(c, -1012, "%s", buf);
532 }
533
534 /**
535 * ea_dump - dump an extended attribute
536 * @e: attribute to be dumped
537 *
538 * ea_dump() dumps contents of the extended attribute given to
539 * the debug output.
540 */
541 void
542 ea_dump(ea_list *e)
543 {
544 int i;
545
546 if (!e)
547 {
548 debug("NONE");
549 return;
550 }
551 while (e)
552 {
553 debug("[%c%c%c]",
554 (e->flags & EALF_SORTED) ? 'S' : 's',
555 (e->flags & EALF_BISECT) ? 'B' : 'b',
556 (e->flags & EALF_CACHED) ? 'C' : 'c');
557 for(i=0; i<e->count; i++)
558 {
559 eattr *a = &e->attrs[i];
560 debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags);
561 if (a->type & EAF_TEMP)
562 debug("T");
563 debug("=%c", "?iO?I?P???S?????" [a->type & EAF_TYPE_MASK]);
564 if (a->type & EAF_ORIGINATED)
565 debug("o");
566 if (a->type & EAF_EMBEDDED)
567 debug(":%08x", a->u.data);
568 else
569 {
570 int j, len = a->u.ptr->length;
571 debug("[%d]:", len);
572 for(j=0; j<len; j++)
573 debug("%02x", a->u.ptr->data[j]);
574 }
575 }
576 if (e = e->next)
577 debug(" | ");
578 }
579 }
580
581 /**
582 * ea_hash - calculate an &ea_list hash key
583 * @e: attribute list
584 *
585 * ea_hash() takes an extended attribute list and calculated a hopefully
586 * uniformly distributed hash value from its contents.
587 */
588 inline unsigned int
589 ea_hash(ea_list *e)
590 {
591 u32 h = 0;
592 int i;
593
594 if (e) /* Assuming chain of length 1 */
595 {
596 for(i=0; i<e->count; i++)
597 {
598 struct eattr *a = &e->attrs[i];
599 h ^= a->id;
600 if (a->type & EAF_EMBEDDED)
601 h ^= a->u.data;
602 else
603 {
604 struct adata *d = a->u.ptr;
605 int size = d->length;
606 byte *z = d->data;
607 while (size >= 4)
608 {
609 h ^= *(u32 *)z;
610 z += 4;
611 size -= 4;
612 }
613 while (size--)
614 h = (h >> 24) ^ (h << 8) ^ *z++;
615 }
616 }
617 h ^= h >> 16;
618 h ^= h >> 6;
619 h &= 0xffff;
620 }
621 return h;
622 }
623
624 /**
625 * ea_append - concatenate &ea_list's
626 * @to: destination list (can be %NULL)
627 * @what: list to be appended (can be %NULL)
628 *
629 * This function appends the &ea_list @what at the end of
630 * &ea_list @to and returns a pointer to the resulting list.
631 */
632 ea_list *
633 ea_append(ea_list *to, ea_list *what)
634 {
635 ea_list *res;
636
637 if (!to)
638 return what;
639 res = to;
640 while (to->next)
641 to = to->next;
642 to->next = what;
643 return res;
644 }
645
646 /*
647 * rta's
648 */
649
650 static unsigned int rta_cache_count;
651 static unsigned int rta_cache_size = 32;
652 static unsigned int rta_cache_limit;
653 static unsigned int rta_cache_mask;
654 static rta **rta_hash_table;
655
656 static void
657 rta_alloc_hash(void)
658 {
659 rta_hash_table = mb_allocz(rta_pool, sizeof(rta *) * rta_cache_size);
660 if (rta_cache_size < 32768)
661 rta_cache_limit = rta_cache_size * 2;
662 else
663 rta_cache_limit = ~0;
664 rta_cache_mask = rta_cache_size - 1;
665 }
666
667 static inline unsigned int
668 rta_hash(rta *a)
669 {
670 return (a->proto->hash_key ^ ipa_hash(a->gw) ^
671 mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
672 }
673
674 static inline int
675 rta_same(rta *x, rta *y)
676 {
677 return (x->proto == y->proto &&
678 x->source == y->source &&
679 x->scope == y->scope &&
680 x->cast == y->cast &&
681 x->dest == y->dest &&
682 x->flags == y->flags &&
683 x->igp_metric == y->igp_metric &&
684 ipa_equal(x->gw, y->gw) &&
685 ipa_equal(x->from, y->from) &&
686 x->iface == y->iface &&
687 x->hostentry == y->hostentry &&
688 mpnh_same(x->nexthops, y->nexthops) &&
689 ea_same(x->eattrs, y->eattrs));
690 }
691
692 static rta *
693 rta_copy(rta *o)
694 {
695 rta *r = sl_alloc(rta_slab);
696
697 memcpy(r, o, sizeof(rta));
698 r->uc = 1;
699 r->nexthops = mpnh_copy(o->nexthops);
700 r->eattrs = ea_list_copy(o->eattrs);
701 return r;
702 }
703
704 static inline void
705 rta_insert(rta *r)
706 {
707 unsigned int h = r->hash_key & rta_cache_mask;
708 r->next = rta_hash_table[h];
709 if (r->next)
710 r->next->pprev = &r->next;
711 r->pprev = &rta_hash_table[h];
712 rta_hash_table[h] = r;
713 }
714
715 static void
716 rta_rehash(void)
717 {
718 unsigned int ohs = rta_cache_size;
719 unsigned int h;
720 rta *r, *n;
721 rta **oht = rta_hash_table;
722
723 rta_cache_size = 2*rta_cache_size;
724 DBG("Rehashing rta cache from %d to %d entries.\n", ohs, rta_cache_size);
725 rta_alloc_hash();
726 for(h=0; h<ohs; h++)
727 for(r=oht[h]; r; r=n)
728 {
729 n = r->next;
730 rta_insert(r);
731 }
732 mb_free(oht);
733 }
734
735 /**
736 * rta_lookup - look up a &rta in attribute cache
737 * @o: a un-cached &rta
738 *
739 * rta_lookup() gets an un-cached &rta structure and returns its cached
740 * counterpart. It starts with examining the attribute cache to see whether
741 * there exists a matching entry. If such an entry exists, it's returned and
742 * its use count is incremented, else a new entry is created with use count
743 * set to 1.
744 *
745 * The extended attribute lists attached to the &rta are automatically
746 * converted to the normalized form.
747 */
748 rta *
749 rta_lookup(rta *o)
750 {
751 rta *r;
752 unsigned int h;
753
754 ASSERT(!(o->aflags & RTAF_CACHED));
755 if (o->eattrs)
756 {
757 if (o->eattrs->next) /* Multiple ea_list's, need to merge them */
758 {
759 ea_list *ml = alloca(ea_scan(o->eattrs));
760 ea_merge(o->eattrs, ml);
761 o->eattrs = ml;
762 }
763 ea_sort(o->eattrs);
764 }
765
766 h = rta_hash(o);
767 for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next)
768 if (r->hash_key == h && rta_same(r, o))
769 return rta_clone(r);
770
771 r = rta_copy(o);
772 r->hash_key = h;
773 r->aflags = RTAF_CACHED;
774 rt_lock_hostentry(r->hostentry);
775 rta_insert(r);
776
777 if (++rta_cache_count > rta_cache_limit)
778 rta_rehash();
779
780 return r;
781 }
782
783 void
784 rta__free(rta *a)
785 {
786 ASSERT(rta_cache_count && (a->aflags & RTAF_CACHED));
787 rta_cache_count--;
788 *a->pprev = a->next;
789 if (a->next)
790 a->next->pprev = a->pprev;
791 a->aflags = 0; /* Poison the entry */
792 rt_unlock_hostentry(a->hostentry);
793 mpnh_free(a->nexthops);
794 ea_free(a->eattrs);
795 sl_free(rta_slab, a);
796 }
797
798 /**
799 * rta_dump - dump route attributes
800 * @a: attribute structure to dump
801 *
802 * This function takes a &rta and dumps its contents to the debug output.
803 */
804 void
805 rta_dump(rta *a)
806 {
807 static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
808 "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
809 "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1",
810 "RTS_OSPF_EXT2", "RTS_BGP" };
811 static char *rtc[] = { "", " BC", " MC", " AC" };
812 static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
813
814 debug("p=%s uc=%d %s %s%s%s h=%04x",
815 a->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
816 rtd[a->dest], a->hash_key);
817 if (!(a->aflags & RTAF_CACHED))
818 debug(" !CACHED");
819 debug(" <-%I", a->from);
820 if (a->dest == RTD_ROUTER)
821 debug(" ->%I", a->gw);
822 if (a->dest == RTD_DEVICE || a->dest == RTD_ROUTER)
823 debug(" [%s]", a->iface ? a->iface->name : "???" );
824 if (a->eattrs)
825 {
826 debug(" EA: ");
827 ea_dump(a->eattrs);
828 }
829 }
830
831 /**
832 * rta_dump_all - dump attribute cache
833 *
834 * This function dumps the whole contents of route attribute cache
835 * to the debug output.
836 */
837 void
838 rta_dump_all(void)
839 {
840 rta *a;
841 unsigned int h;
842
843 debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
844 for(h=0; h<rta_cache_size; h++)
845 for(a=rta_hash_table[h]; a; a=a->next)
846 {
847 debug("%p ", a);
848 rta_dump(a);
849 debug("\n");
850 }
851 debug("\n");
852 }
853
854 void
855 rta_show(struct cli *c, rta *a, ea_list *eal)
856 {
857 static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
858 "RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" };
859 static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
860 int i;
861
862 cli_printf(c, -1008, "\tType: %s %s %s", src_names[a->source], cast_names[a->cast], ip_scope_text(a->scope));
863 if (!eal)
864 eal = a->eattrs;
865 for(; eal; eal=eal->next)
866 for(i=0; i<eal->count; i++)
867 ea_show(c, &eal->attrs[i]);
868 }
869
870 /**
871 * rta_init - initialize route attribute cache
872 *
873 * This function is called during initialization of the routing
874 * table module to set up the internals of the attribute cache.
875 */
876 void
877 rta_init(void)
878 {
879 rta_pool = rp_new(&root_pool, "Attributes");
880 rta_slab = sl_new(rta_pool, sizeof(rta));
881 mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh));
882 rta_alloc_hash();
883 }
884
885 /*
886 * Documentation for functions declared inline in route.h
887 */
888 #if 0
889
890 /**
891 * rta_clone - clone route attributes
892 * @r: a &rta to be cloned
893 *
894 * rta_clone() takes a cached &rta and returns its identical cached
895 * copy. Currently it works by just returning the original &rta with
896 * its use count incremented.
897 */
898 static inline rta *rta_clone(rta *r)
899 { DUMMY; }
900
901 /**
902 * rta_free - free route attributes
903 * @r: a &rta to be freed
904 *
905 * If you stop using a &rta (for example when deleting a route which uses
906 * it), you need to call rta_free() to notify the attribute cache the
907 * attribute is no longer in use and can be freed if you were the last
908 * user (which rta_free() tests by inspecting the use count).
909 */
910 static inline void rta_free(rta *r)
911 { DUMMY; }
912
913 #endif