Annotation of embedaddon/quagga/bgpd/bgp_aspath.c, revision 1.1.1.1
1.1 misho 1: /* AS path management routines.
2: Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
3: Copyright (C) 2005 Sun Microsystems, Inc.
4:
5: This file is part of GNU Zebra.
6:
7: GNU Zebra is free software; you can redistribute it and/or modify it
8: under the terms of the GNU General Public License as published by the
9: Free Software Foundation; either version 2, or (at your option) any
10: later version.
11:
12: GNU Zebra is distributed in the hope that it will be useful, but
13: WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with GNU Zebra; see the file COPYING. If not, write to the Free
19: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20: 02111-1307, USA. */
21:
22: #include <zebra.h>
23:
24: #include "hash.h"
25: #include "memory.h"
26: #include "vector.h"
27: #include "vty.h"
28: #include "str.h"
29: #include "log.h"
30: #include "stream.h"
31: #include "jhash.h"
32:
33: #include "bgpd/bgpd.h"
34: #include "bgpd/bgp_aspath.h"
35: #include "bgpd/bgp_debug.h"
36: #include "bgpd/bgp_attr.h"
37:
38: /* Attr. Flags and Attr. Type Code. */
39: #define AS_HEADER_SIZE 2
40:
41: /* Now FOUR octets are used for AS value. */
42: #define AS_VALUE_SIZE sizeof (as_t)
43: /* This is the old one */
44: #define AS16_VALUE_SIZE sizeof (as16_t)
45:
46: /* Maximum protocol segment length value */
47: #define AS_SEGMENT_MAX 255
48:
49: /* The following length and size macros relate specifically to Quagga's
50: * internal representation of AS-Segments, not per se to the on-wire
51: * sizes and lengths. At present (200508) they sort of match, however
52: * the ONLY functions which should now about the on-wire syntax are
53: * aspath_put, assegment_put and assegment_parse.
54: *
55: * aspath_put returns bytes written, the only definitive record of
56: * size of wire-format attribute..
57: */
58:
59: /* Calculated size in bytes of ASN segment data to hold N ASN's */
60: #define ASSEGMENT_DATA_SIZE(N,S) \
61: ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) )
62:
63: /* Calculated size of segment struct to hold N ASN's */
64: #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S))
65:
66: /* AS segment octet length. */
67: #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S)
68:
69: /* AS_SEQUENCE segments can be packed together */
70: /* Can the types of X and Y be considered for packing? */
71: #define ASSEGMENT_TYPES_PACKABLE(X,Y) \
72: ( ((X)->type == (Y)->type) \
73: && ((X)->type == AS_SEQUENCE))
74: /* Types and length of X,Y suitable for packing? */
75: #define ASSEGMENTS_PACKABLE(X,Y) \
76: ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \
77: && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) )
78:
79: /* As segment header - the on-wire representation
80: * NOT the internal representation!
81: */
82: struct assegment_header
83: {
84: u_char type;
85: u_char length;
86: };
87:
88: /* Hash for aspath. This is the top level structure of AS path. */
89: static struct hash *ashash;
90:
91: /* Stream for SNMP. See aspath_snmp_pathseg */
92: static struct stream *snmp_stream;
93:
94: static inline as_t *
95: assegment_data_new (int num)
96: {
97: return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));
98: }
99:
100: static inline void
101: assegment_data_free (as_t *asdata)
102: {
103: XFREE (MTYPE_AS_SEG_DATA,asdata);
104: }
105:
106: /* Get a new segment. Note that 0 is an allowed length,
107: * and will result in a segment with no allocated data segment.
108: * the caller should immediately assign data to the segment, as the segment
109: * otherwise is not generally valid
110: */
111: static struct assegment *
112: assegment_new (u_char type, u_short length)
113: {
114: struct assegment *new;
115:
116: new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment));
117:
118: if (length)
119: new->as = assegment_data_new (length);
120:
121: new->length = length;
122: new->type = type;
123:
124: return new;
125: }
126:
127: static void
128: assegment_free (struct assegment *seg)
129: {
130: if (!seg)
131: return;
132:
133: if (seg->as)
134: XFREE (MTYPE_AS_SEG_DATA, seg->as);
135: memset (seg, 0xfe, sizeof(struct assegment));
136: XFREE (MTYPE_AS_SEG, seg);
137:
138: return;
139: }
140:
141: /* free entire chain of segments */
142: static void
143: assegment_free_all (struct assegment *seg)
144: {
145: struct assegment *prev;
146:
147: while (seg)
148: {
149: prev = seg;
150: seg = seg->next;
151: assegment_free (prev);
152: }
153: }
154:
155: /* Duplicate just the given assegment and its data */
156: static struct assegment *
157: assegment_dup (struct assegment *seg)
158: {
159: struct assegment *new;
160:
161: new = assegment_new (seg->type, seg->length);
162: memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) );
163:
164: return new;
165: }
166:
167: /* Duplicate entire chain of assegments, return the head */
168: static struct assegment *
169: assegment_dup_all (struct assegment *seg)
170: {
171: struct assegment *new = NULL;
172: struct assegment *head = NULL;
173:
174: while (seg)
175: {
176: if (head)
177: {
178: new->next = assegment_dup (seg);
179: new = new->next;
180: }
181: else
182: head = new = assegment_dup (seg);
183:
184: seg = seg->next;
185: }
186: return head;
187: }
188:
189: /* prepend the as number to given segment, given num of times */
190: static struct assegment *
191: assegment_prepend_asns (struct assegment *seg, as_t asnum, int num)
192: {
193: as_t *newas;
194:
195: if (!num)
196: return seg;
197:
198: if (num >= AS_SEGMENT_MAX)
199: return seg; /* we don't do huge prepends */
200:
201: newas = assegment_data_new (seg->length + num);
202:
203: if (newas)
204: {
205: int i;
206: for (i = 0; i < num; i++)
207: newas[i] = asnum;
208:
209: memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1));
210: XFREE (MTYPE_AS_SEG_DATA, seg->as);
211: seg->as = newas;
212: seg->length += num;
213: return seg;
214: }
215:
216: assegment_free_all (seg);
217: return NULL;
218: }
219:
220: /* append given array of as numbers to the segment */
221: static struct assegment *
222: assegment_append_asns (struct assegment *seg, as_t *asnos, int num)
223: {
224: as_t *newas;
225:
226: newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as,
227: ASSEGMENT_DATA_SIZE (seg->length + num, 1));
228:
229: if (newas)
230: {
231: seg->as = newas;
232: memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1));
233: seg->length += num;
234: return seg;
235: }
236:
237: assegment_free_all (seg);
238: return NULL;
239: }
240:
241: static int
242: int_cmp (const void *p1, const void *p2)
243: {
244: const as_t *as1 = p1;
245: const as_t *as2 = p2;
246:
247: return (*as1 == *as2)
248: ? 0 : ( (*as1 > *as2) ? 1 : -1);
249: }
250:
251: /* normalise the segment.
252: * In particular, merge runs of AS_SEQUENCEs into one segment
253: * Internally, we do not care about the wire segment length limit, and
254: * we want each distinct AS_PATHs to have the exact same internal
255: * representation - eg, so that our hashing actually works..
256: */
257: static struct assegment *
258: assegment_normalise (struct assegment *head)
259: {
260: struct assegment *seg = head, *pin;
261: struct assegment *tmp;
262:
263: if (!head)
264: return head;
265:
266: while (seg)
267: {
268: pin = seg;
269:
270: /* Sort values SET segments, for determinism in paths to aid
271: * creation of hash values / path comparisons
272: * and because it helps other lesser implementations ;)
273: */
274: if (seg->type == AS_SET || seg->type == AS_CONFED_SET)
275: {
276: int tail = 0;
277: int i;
278:
279: qsort (seg->as, seg->length, sizeof(as_t), int_cmp);
280:
281: /* weed out dupes */
282: for (i=1; i < seg->length; i++)
283: {
284: if (seg->as[tail] == seg->as[i])
285: continue;
286:
287: tail++;
288: if (tail < i)
289: seg->as[tail] = seg->as[i];
290: }
291: /* seg->length can be 0.. */
292: if (seg->length)
293: seg->length = tail + 1;
294: }
295:
296: /* read ahead from the current, pinned segment while the segments
297: * are packable/mergeable. Append all following packable segments
298: * to the segment we have pinned and remove these appended
299: * segments.
300: */
301: while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next))
302: {
303: tmp = pin->next;
304: seg = pin->next;
305:
306: /* append the next sequence to the pinned sequence */
307: pin = assegment_append_asns (pin, seg->as, seg->length);
308:
309: /* bypass the next sequence */
310: pin->next = seg->next;
311:
312: /* get rid of the now referenceless segment */
313: assegment_free (tmp);
314:
315: }
316:
317: seg = pin->next;
318: }
319: return head;
320: }
321:
322: static struct aspath *
323: aspath_new (void)
324: {
325: return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
326: }
327:
328: /* Free AS path structure. */
329: void
330: aspath_free (struct aspath *aspath)
331: {
332: if (!aspath)
333: return;
334: if (aspath->segments)
335: assegment_free_all (aspath->segments);
336: if (aspath->str)
337: XFREE (MTYPE_AS_STR, aspath->str);
338: XFREE (MTYPE_AS_PATH, aspath);
339: }
340:
341: /* Unintern aspath from AS path bucket. */
342: void
343: aspath_unintern (struct aspath **aspath)
344: {
345: struct aspath *ret;
346: struct aspath *asp = *aspath;
347:
348: if (asp->refcnt)
349: asp->refcnt--;
350:
351: if (asp->refcnt == 0)
352: {
353: /* This aspath must exist in aspath hash table. */
354: ret = hash_release (ashash, asp);
355: assert (ret != NULL);
356: aspath_free (asp);
357: *aspath = NULL;
358: }
359: }
360:
361: /* Return the start or end delimiters for a particular Segment type */
362: #define AS_SEG_START 0
363: #define AS_SEG_END 1
364: static char
365: aspath_delimiter_char (u_char type, u_char which)
366: {
367: int i;
368: struct
369: {
370: int type;
371: char start;
372: char end;
373: } aspath_delim_char [] =
374: {
375: { AS_SET, '{', '}' },
376: { AS_CONFED_SET, '[', ']' },
377: { AS_CONFED_SEQUENCE, '(', ')' },
378: { 0 }
379: };
380:
381: for (i = 0; aspath_delim_char[i].type != 0; i++)
382: {
383: if (aspath_delim_char[i].type == type)
384: {
385: if (which == AS_SEG_START)
386: return aspath_delim_char[i].start;
387: else if (which == AS_SEG_END)
388: return aspath_delim_char[i].end;
389: }
390: }
391: return ' ';
392: }
393:
394: /* countup asns from this segment and index onward */
395: static int
396: assegment_count_asns (struct assegment *seg, int from)
397: {
398: int count = 0;
399: while (seg)
400: {
401: if (!from)
402: count += seg->length;
403: else
404: {
405: count += (seg->length - from);
406: from = 0;
407: }
408: seg = seg->next;
409: }
410: return count;
411: }
412:
413: unsigned int
414: aspath_count_confeds (struct aspath *aspath)
415: {
416: int count = 0;
417: struct assegment *seg = aspath->segments;
418:
419: while (seg)
420: {
421: if (seg->type == AS_CONFED_SEQUENCE)
422: count += seg->length;
423: else if (seg->type == AS_CONFED_SET)
424: count++;
425:
426: seg = seg->next;
427: }
428: return count;
429: }
430:
431: unsigned int
432: aspath_count_hops (struct aspath *aspath)
433: {
434: int count = 0;
435: struct assegment *seg = aspath->segments;
436:
437: while (seg)
438: {
439: if (seg->type == AS_SEQUENCE)
440: count += seg->length;
441: else if (seg->type == AS_SET)
442: count++;
443:
444: seg = seg->next;
445: }
446: return count;
447: }
448:
449: /* Estimate size aspath /might/ take if encoded into an
450: * ASPATH attribute.
451: *
452: * This is a quick estimate, not definitive! aspath_put()
453: * may return a different number!!
454: */
455: unsigned int
456: aspath_size (struct aspath *aspath)
457: {
458: int size = 0;
459: struct assegment *seg = aspath->segments;
460:
461: while (seg)
462: {
463: size += ASSEGMENT_SIZE(seg->length, 1);
464: seg = seg->next;
465: }
466: return size;
467: }
468:
469: /* Return highest public ASN in path */
470: as_t
471: aspath_highest (struct aspath *aspath)
472: {
473: struct assegment *seg = aspath->segments;
474: as_t highest = 0;
475: unsigned int i;
476:
477: while (seg)
478: {
479: for (i = 0; i < seg->length; i++)
480: if (seg->as[i] > highest
481: && (seg->as[i] < BGP_PRIVATE_AS_MIN
482: || seg->as[i] > BGP_PRIVATE_AS_MAX))
483: highest = seg->as[i];
484: seg = seg->next;
485: }
486: return highest;
487: }
488:
489: /* Return 1 if there are any 4-byte ASes in the path */
490: unsigned int
491: aspath_has_as4 (struct aspath *aspath)
492: {
493: struct assegment *seg = aspath->segments;
494: unsigned int i;
495:
496: while (seg)
497: {
498: for (i = 0; i < seg->length; i++)
499: if (seg->as[i] > BGP_AS_MAX)
500: return 1;
501: seg = seg->next;
502: }
503: return 0;
504: }
505:
506: /* Convert aspath structure to string expression. */
507: static char *
508: aspath_make_str_count (struct aspath *as)
509: {
510: struct assegment *seg;
511: int str_size;
512: int len = 0;
513: char *str_buf;
514:
515: /* Empty aspath. */
516: if (!as->segments)
517: {
518: str_buf = XMALLOC (MTYPE_AS_STR, 1);
519: str_buf[0] = '\0';
520: return str_buf;
521: }
522:
523: seg = as->segments;
524:
525: /* ASN takes 5 to 10 chars plus seperator, see below.
526: * If there is one differing segment type, we need an additional
527: * 2 chars for segment delimiters, and the final '\0'.
528: * Hopefully this is large enough to avoid hitting the realloc
529: * code below for most common sequences.
530: *
531: * This was changed to 10 after the well-known BGP assertion, which
532: * had hit some parts of the Internet in May of 2009.
533: */
534: #define ASN_STR_LEN (10 + 1)
535: str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1,
536: ASPATH_STR_DEFAULT_LEN);
537: str_buf = XMALLOC (MTYPE_AS_STR, str_size);
538:
539: while (seg)
540: {
541: int i;
542: char seperator;
543:
544: /* Check AS type validity. Set seperator for segment */
545: switch (seg->type)
546: {
547: case AS_SET:
548: case AS_CONFED_SET:
549: seperator = ',';
550: break;
551: case AS_SEQUENCE:
552: case AS_CONFED_SEQUENCE:
553: seperator = ' ';
554: break;
555: default:
556: XFREE (MTYPE_AS_STR, str_buf);
557: return NULL;
558: }
559:
560: /* We might need to increase str_buf, particularly if path has
561: * differing segments types, our initial guesstimate above will
562: * have been wrong. Need 10 chars for ASN, a seperator each and
563: * potentially two segment delimiters, plus a space between each
564: * segment and trailing zero.
565: *
566: * This definitely didn't work with the value of 5 bytes and
567: * 32-bit ASNs.
568: */
569: #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1)
570: if ( (len + SEGMENT_STR_LEN(seg)) > str_size)
571: {
572: str_size = len + SEGMENT_STR_LEN(seg);
573: str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size);
574: }
575: #undef ASN_STR_LEN
576: #undef SEGMENT_STR_LEN
577:
578: if (seg->type != AS_SEQUENCE)
579: len += snprintf (str_buf + len, str_size - len,
580: "%c",
581: aspath_delimiter_char (seg->type, AS_SEG_START));
582:
583: /* write out the ASNs, with their seperators, bar the last one*/
584: for (i = 0; i < seg->length; i++)
585: {
586: len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]);
587:
588: if (i < (seg->length - 1))
589: len += snprintf (str_buf + len, str_size - len, "%c", seperator);
590: }
591:
592: if (seg->type != AS_SEQUENCE)
593: len += snprintf (str_buf + len, str_size - len, "%c",
594: aspath_delimiter_char (seg->type, AS_SEG_END));
595: if (seg->next)
596: len += snprintf (str_buf + len, str_size - len, " ");
597:
598: seg = seg->next;
599: }
600:
601: assert (len < str_size);
602:
603: str_buf[len] = '\0';
604:
605: return str_buf;
606: }
607:
608: static void
609: aspath_str_update (struct aspath *as)
610: {
611: if (as->str)
612: XFREE (MTYPE_AS_STR, as->str);
613: as->str = aspath_make_str_count (as);
614: }
615:
616: /* Intern allocated AS path. */
617: struct aspath *
618: aspath_intern (struct aspath *aspath)
619: {
620: struct aspath *find;
621:
622: /* Assert this AS path structure is not interned. */
623: assert (aspath->refcnt == 0);
624:
625: /* Check AS path hash. */
626: find = hash_get (ashash, aspath, hash_alloc_intern);
627:
628: if (find != aspath)
629: aspath_free (aspath);
630:
631: find->refcnt++;
632:
633: if (! find->str)
634: find->str = aspath_make_str_count (find);
635:
636: return find;
637: }
638:
639: /* Duplicate aspath structure. Created same aspath structure but
640: reference count and AS path string is cleared. */
641: struct aspath *
642: aspath_dup (struct aspath *aspath)
643: {
644: struct aspath *new;
645:
646: new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath));
647:
648: if (aspath->segments)
649: new->segments = assegment_dup_all (aspath->segments);
650: else
651: new->segments = NULL;
652:
653: new->str = aspath_make_str_count (aspath);
654:
655: return new;
656: }
657:
658: static void *
659: aspath_hash_alloc (void *arg)
660: {
661: struct aspath *aspath;
662:
663: /* New aspath structure is needed. */
664: aspath = aspath_dup (arg);
665:
666: /* Malformed AS path value. */
667: if (! aspath->str)
668: {
669: aspath_free (aspath);
670: return NULL;
671: }
672:
673: return aspath;
674: }
675:
676: /* parse as-segment byte stream in struct assegment */
677: static int
678: assegments_parse (struct stream *s, size_t length,
679: struct assegment **result, int use32bit)
680: {
681: struct assegment_header segh;
682: struct assegment *seg, *prev = NULL, *head = NULL;
683: size_t bytes = 0;
684:
685: /* empty aspath (ie iBGP or somesuch) */
686: if (length == 0)
687: return 0;
688:
689: if (BGP_DEBUG (as4, AS4_SEGMENT))
690: zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",
691: (unsigned long) length);
692: /* basic checks */
693: if ((STREAM_READABLE(s) < length)
694: || (STREAM_READABLE(s) < AS_HEADER_SIZE)
695: || (length % AS16_VALUE_SIZE ))
696: return -1;
697:
698: while (bytes < length)
699: {
700: int i;
701: size_t seg_size;
702:
703: if ((length - bytes) <= AS_HEADER_SIZE)
704: {
705: if (head)
706: assegment_free_all (head);
707: return -1;
708: }
709:
710: /* softly softly, get the header first on its own */
711: segh.type = stream_getc (s);
712: segh.length = stream_getc (s);
713:
714: seg_size = ASSEGMENT_SIZE(segh.length, use32bit);
715:
716: if (BGP_DEBUG (as4, AS4_SEGMENT))
717: zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",
718: segh.type, segh.length);
719:
720: /* check it.. */
721: if ( ((bytes + seg_size) > length)
722: /* 1771bis 4.3b: seg length contains one or more */
723: || (segh.length == 0)
724: /* Paranoia in case someone changes type of segment length.
725: * Shift both values by 0x10 to make the comparison operate
726: * on more, than 8 bits (otherwise it's a warning, bug #564).
727: */
728: || ((sizeof segh.length > 1)
729: && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
730: {
731: if (head)
732: assegment_free_all (head);
733: return -1;
734: }
735:
736: switch (segh.type)
737: {
738: case AS_SEQUENCE:
739: case AS_SET:
740: case AS_CONFED_SEQUENCE:
741: case AS_CONFED_SET:
742: break;
743: default:
744: if (head)
745: assegment_free_all (head);
746: return -1;
747: }
748:
749: /* now its safe to trust lengths */
750: seg = assegment_new (segh.type, segh.length);
751:
752: if (head)
753: prev->next = seg;
754: else /* it's the first segment */
755: head = prev = seg;
756:
757: for (i = 0; i < segh.length; i++)
758: seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s);
759:
760: bytes += seg_size;
761:
762: if (BGP_DEBUG (as4, AS4_SEGMENT))
763: zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu",
764: (unsigned long) bytes);
765:
766: prev = seg;
767: }
768:
769: *result = assegment_normalise (head);
770: return 0;
771: }
772:
773: /* AS path parse function. pnt is a pointer to byte stream and length
774: is length of byte stream. If there is same AS path in the the AS
775: path hash then return it else make new AS path structure.
776:
777: On error NULL is returned.
778: */
779: struct aspath *
780: aspath_parse (struct stream *s, size_t length, int use32bit)
781: {
782: struct aspath as;
783: struct aspath *find;
784:
785: /* If length is odd it's malformed AS path. */
786: /* Nit-picking: if (use32bit == 0) it is malformed if odd,
787: * otherwise its malformed when length is larger than 2 and (length-2)
788: * is not dividable by 4.
789: * But... this time we're lazy
790: */
791: if (length % AS16_VALUE_SIZE )
792: return NULL;
793:
794: memset (&as, 0, sizeof (struct aspath));
795: if (assegments_parse (s, length, &as.segments, use32bit) < 0)
796: return NULL;
797:
798: /* If already same aspath exist then return it. */
799: find = hash_get (ashash, &as, aspath_hash_alloc);
800:
801: /* aspath_hash_alloc dupes segments too. that probably could be
802: * optimised out.
803: */
804: assegment_free_all (as.segments);
805: if (as.str)
806: XFREE (MTYPE_AS_STR, as.str);
807:
808: if (! find)
809: return NULL;
810: find->refcnt++;
811:
812: return find;
813: }
814:
815: static inline void
816: assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)
817: {
818: int i;
819: assert (num <= AS_SEGMENT_MAX);
820:
821: for (i = 0; i < num; i++)
822: if ( use32bit )
823: stream_putl (s, as[i]);
824: else
825: {
826: if ( as[i] <= BGP_AS_MAX )
827: stream_putw(s, as[i]);
828: else
829: stream_putw(s, BGP_AS_TRANS);
830: }
831: }
832:
833: static inline size_t
834: assegment_header_put (struct stream *s, u_char type, int length)
835: {
836: size_t lenp;
837: assert (length <= AS_SEGMENT_MAX);
838: stream_putc (s, type);
839: lenp = stream_get_endp (s);
840: stream_putc (s, length);
841: return lenp;
842: }
843:
844: /* write aspath data to stream */
845: size_t
846: aspath_put (struct stream *s, struct aspath *as, int use32bit )
847: {
848: struct assegment *seg = as->segments;
849: size_t bytes = 0;
850:
851: if (!seg || seg->length == 0)
852: return 0;
853:
854: if (seg)
855: {
856: /*
857: * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
858: * At the moment, we would write out a partial aspath, and our peer
859: * will complain and drop the session :-/
860: *
861: * The general assumption here is that many things tested will
862: * never happen. And, in real live, up to now, they have not.
863: */
864: while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s)))
865: {
866: struct assegment *next = seg->next;
867: int written = 0;
868: int asns_packed = 0;
869: size_t lenp;
870:
871: /* Overlength segments have to be split up */
872: while ( (seg->length - written) > AS_SEGMENT_MAX)
873: {
874: assegment_header_put (s, seg->type, AS_SEGMENT_MAX);
875: assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit);
876: written += AS_SEGMENT_MAX;
877: bytes += ASSEGMENT_SIZE (written, use32bit);
878: }
879:
880: /* write the final segment, probably is also the first */
881: lenp = assegment_header_put (s, seg->type, seg->length - written);
882: assegment_data_put (s, (seg->as + written), seg->length - written,
883: use32bit);
884:
885: /* Sequence-type segments can be 'packed' together
886: * Case of a segment which was overlength and split up
887: * will be missed here, but that doesn't matter.
888: */
889: while (next && ASSEGMENTS_PACKABLE (seg, next))
890: {
891: /* NB: We should never normally get here given we
892: * normalise aspath data when parse them. However, better
893: * safe than sorry. We potentially could call
894: * assegment_normalise here instead, but it's cheaper and
895: * easier to do it on the fly here rather than go through
896: * the segment list twice every time we write out
897: * aspath's.
898: */
899:
900: /* Next segment's data can fit in this one */
901: assegment_data_put (s, next->as, next->length, use32bit);
902:
903: /* update the length of the segment header */
904: stream_putc_at (s, lenp, seg->length - written + next->length);
905: asns_packed += next->length;
906:
907: next = next->next;
908: }
909:
910: bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed,
911: use32bit);
912: seg = next;
913: }
914: }
915: return bytes;
916: }
917:
918: /* This is for SNMP BGP4PATHATTRASPATHSEGMENT
919: * We have no way to manage the storage, so we use a static stream
920: * wrapper around aspath_put.
921: */
922: u_char *
923: aspath_snmp_pathseg (struct aspath *as, size_t *varlen)
924: {
925: #define SNMP_PATHSEG_MAX 1024
926:
927: if (!snmp_stream)
928: snmp_stream = stream_new (SNMP_PATHSEG_MAX);
929: else
930: stream_reset (snmp_stream);
931:
932: if (!as)
933: {
934: *varlen = 0;
935: return NULL;
936: }
937: aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */
938:
939: *varlen = stream_get_endp (snmp_stream);
940: return stream_pnt(snmp_stream);
941: }
942:
943: #define min(A,B) ((A) < (B) ? (A) : (B))
944:
945: static struct assegment *
946: aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset,
947: as_t as)
948: {
949: int i;
950:
951: /* If this is first AS set member, create new as-set segment. */
952: if (asset == NULL)
953: {
954: asset = assegment_new (AS_SET, 1);
955: if (! aspath->segments)
956: aspath->segments = asset;
957: else
958: {
959: struct assegment *seg = aspath->segments;
960: while (seg->next)
961: seg = seg->next;
962: seg->next = asset;
963: }
964: asset->type = AS_SET;
965: asset->length = 1;
966: asset->as[0] = as;
967: }
968: else
969: {
970: /* Check this AS value already exists or not. */
971: for (i = 0; i < asset->length; i++)
972: if (asset->as[i] == as)
973: return asset;
974:
975: asset->length++;
976: asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as,
977: asset->length * AS_VALUE_SIZE);
978: asset->as[asset->length - 1] = as;
979: }
980:
981:
982: return asset;
983: }
984:
985: /* Modify as1 using as2 for aggregation. */
986: struct aspath *
987: aspath_aggregate (struct aspath *as1, struct aspath *as2)
988: {
989: int i;
990: int minlen;
991: int match;
992: int from;
993: struct assegment *seg1 = as1->segments;
994: struct assegment *seg2 = as2->segments;
995: struct aspath *aspath = NULL;
996: struct assegment *asset;
997: struct assegment *prevseg = NULL;
998:
999: match = 0;
1000: minlen = 0;
1001: aspath = NULL;
1002: asset = NULL;
1003:
1004: /* First of all check common leading sequence. */
1005: while (seg1 && seg2)
1006: {
1007: /* Check segment type. */
1008: if (seg1->type != seg2->type)
1009: break;
1010:
1011: /* Minimum segment length. */
1012: minlen = min (seg1->length, seg2->length);
1013:
1014: for (match = 0; match < minlen; match++)
1015: if (seg1->as[match] != seg2->as[match])
1016: break;
1017:
1018: if (match)
1019: {
1020: struct assegment *seg = assegment_new (seg1->type, 0);
1021:
1022: seg = assegment_append_asns (seg, seg1->as, match);
1023:
1024: if (! aspath)
1025: {
1026: aspath = aspath_new ();
1027: aspath->segments = seg;
1028: }
1029: else
1030: prevseg->next = seg;
1031:
1032: prevseg = seg;
1033: }
1034:
1035: if (match != minlen || match != seg1->length
1036: || seg1->length != seg2->length)
1037: break;
1038:
1039: seg1 = seg1->next;
1040: seg2 = seg2->next;
1041: }
1042:
1043: if (! aspath)
1044: aspath = aspath_new();
1045:
1046: /* Make as-set using rest of all information. */
1047: from = match;
1048: while (seg1)
1049: {
1050: for (i = from; i < seg1->length; i++)
1051: asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]);
1052:
1053: from = 0;
1054: seg1 = seg1->next;
1055: }
1056:
1057: from = match;
1058: while (seg2)
1059: {
1060: for (i = from; i < seg2->length; i++)
1061: asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]);
1062:
1063: from = 0;
1064: seg2 = seg2->next;
1065: }
1066:
1067: assegment_normalise (aspath->segments);
1068: aspath_str_update (aspath);
1069: return aspath;
1070: }
1071:
1072: /* When a BGP router receives an UPDATE with an MP_REACH_NLRI
1073: attribute, check the leftmost AS number in the AS_PATH attribute is
1074: or not the peer's AS number. */
1075: int
1076: aspath_firstas_check (struct aspath *aspath, as_t asno)
1077: {
1078: if ( (aspath == NULL) || (aspath->segments == NULL) )
1079: return 0;
1080:
1081: if (aspath->segments
1082: && (aspath->segments->type == AS_SEQUENCE)
1083: && (aspath->segments->as[0] == asno ))
1084: return 1;
1085:
1086: return 0;
1087: }
1088:
1089: /* AS path loop check. If aspath contains asno then return >= 1. */
1090: int
1091: aspath_loop_check (struct aspath *aspath, as_t asno)
1092: {
1093: struct assegment *seg;
1094: int count = 0;
1095:
1096: if ( (aspath == NULL) || (aspath->segments == NULL) )
1097: return 0;
1098:
1099: seg = aspath->segments;
1100:
1101: while (seg)
1102: {
1103: int i;
1104:
1105: for (i = 0; i < seg->length; i++)
1106: if (seg->as[i] == asno)
1107: count++;
1108:
1109: seg = seg->next;
1110: }
1111: return count;
1112: }
1113:
1114: /* When all of AS path is private AS return 1. */
1115: int
1116: aspath_private_as_check (struct aspath *aspath)
1117: {
1118: struct assegment *seg;
1119:
1120: if ( !(aspath && aspath->segments) )
1121: return 0;
1122:
1123: seg = aspath->segments;
1124:
1125: while (seg)
1126: {
1127: int i;
1128:
1129: for (i = 0; i < seg->length; i++)
1130: {
1131: if ( (seg->as[i] < BGP_PRIVATE_AS_MIN)
1132: || (seg->as[i] > BGP_PRIVATE_AS_MAX) )
1133: return 0;
1134: }
1135: seg = seg->next;
1136: }
1137: return 1;
1138: }
1139:
1140: /* AS path confed check. If aspath contains confed set or sequence then return 1. */
1141: int
1142: aspath_confed_check (struct aspath *aspath)
1143: {
1144: struct assegment *seg;
1145:
1146: if ( !(aspath && aspath->segments) )
1147: return 0;
1148:
1149: seg = aspath->segments;
1150:
1151: while (seg)
1152: {
1153: if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE)
1154: return 1;
1155: seg = seg->next;
1156: }
1157: return 0;
1158: }
1159:
1160: /* Leftmost AS path segment confed check. If leftmost AS segment is of type
1161: AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */
1162: int
1163: aspath_left_confed_check (struct aspath *aspath)
1164: {
1165:
1166: if ( !(aspath && aspath->segments) )
1167: return 0;
1168:
1169: if ( (aspath->segments->type == AS_CONFED_SEQUENCE)
1170: || (aspath->segments->type == AS_CONFED_SET) )
1171: return 1;
1172:
1173: return 0;
1174: }
1175:
1176: /* Merge as1 to as2. as2 should be uninterned aspath. */
1177: static struct aspath *
1178: aspath_merge (struct aspath *as1, struct aspath *as2)
1179: {
1180: struct assegment *last, *new;
1181:
1182: if (! as1 || ! as2)
1183: return NULL;
1184:
1185: last = new = assegment_dup_all (as1->segments);
1186:
1187: /* find the last valid segment */
1188: while (last && last->next)
1189: last = last->next;
1190:
1191: last->next = as2->segments;
1192: as2->segments = new;
1193: aspath_str_update (as2);
1194: return as2;
1195: }
1196:
1197: /* Prepend as1 to as2. as2 should be uninterned aspath. */
1198: struct aspath *
1199: aspath_prepend (struct aspath *as1, struct aspath *as2)
1200: {
1201: struct assegment *seg1;
1202: struct assegment *seg2;
1203:
1204: if (! as1 || ! as2)
1205: return NULL;
1206:
1207: seg1 = as1->segments;
1208: seg2 = as2->segments;
1209:
1210: /* If as2 is empty, only need to dupe as1's chain onto as2 */
1211: if (seg2 == NULL)
1212: {
1213: as2->segments = assegment_dup_all (as1->segments);
1214: aspath_str_update (as2);
1215: return as2;
1216: }
1217:
1218: /* If as1 is empty AS, no prepending to do. */
1219: if (seg1 == NULL)
1220: return as2;
1221:
1222: /* find the tail as1's segment chain. */
1223: while (seg1 && seg1->next)
1224: seg1 = seg1->next;
1225:
1226: /* Delete any AS_CONFED_SEQUENCE segment from as2. */
1227: if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
1228: as2 = aspath_delete_confed_seq (as2);
1229:
1230: /* Compare last segment type of as1 and first segment type of as2. */
1231: if (seg1->type != seg2->type)
1232: return aspath_merge (as1, as2);
1233:
1234: if (seg1->type == AS_SEQUENCE)
1235: {
1236: /* We have two chains of segments, as1->segments and seg2,
1237: * and we have to attach them together, merging the attaching
1238: * segments together into one.
1239: *
1240: * 1. dupe as1->segments onto head of as2
1241: * 2. merge seg2's asns onto last segment of this new chain
1242: * 3. attach chain after seg2
1243: */
1244:
1245: /* dupe as1 onto as2's head */
1246: seg1 = as2->segments = assegment_dup_all (as1->segments);
1247:
1248: /* refind the tail of as2, reusing seg1 */
1249: while (seg1 && seg1->next)
1250: seg1 = seg1->next;
1251:
1252: /* merge the old head, seg2, into tail, seg1 */
1253: seg1 = assegment_append_asns (seg1, seg2->as, seg2->length);
1254:
1255: /* bypass the merged seg2, and attach any chain after it to
1256: * chain descending from as2's head
1257: */
1258: seg1->next = seg2->next;
1259:
1260: /* seg2 is now referenceless and useless*/
1261: assegment_free (seg2);
1262:
1263: /* we've now prepended as1's segment chain to as2, merging
1264: * the inbetween AS_SEQUENCE of seg2 in the process
1265: */
1266: aspath_str_update (as2);
1267: return as2;
1268: }
1269: else
1270: {
1271: /* AS_SET merge code is needed at here. */
1272: return aspath_merge (as1, as2);
1273: }
1274: /* XXX: Ermmm, what if as1 has multiple segments?? */
1275:
1276: /* Not reached */
1277: }
1278:
1279: /* Iterate over AS_PATH segments and wipe all occurences of the
1280: * listed AS numbers. Hence some segments may lose some or even
1281: * all data on the way, the operation is implemented as a smarter
1282: * version of aspath_dup(), which allocates memory to hold the new
1283: * data, not the original. The new AS path is returned.
1284: */
1285: struct aspath *
1286: aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list)
1287: {
1288: struct assegment * srcseg, * exclseg, * lastseg;
1289: struct aspath * newpath;
1290:
1291: newpath = aspath_new();
1292: lastseg = NULL;
1293:
1294: for (srcseg = source->segments; srcseg; srcseg = srcseg->next)
1295: {
1296: unsigned i, y, newlen = 0, done = 0, skip_as;
1297: struct assegment * newseg;
1298:
1299: /* Find out, how much ASns are we going to pick from this segment.
1300: * We can't perform filtering right inline, because the size of
1301: * the new segment isn't known at the moment yet.
1302: */
1303: for (i = 0; i < srcseg->length; i++)
1304: {
1305: skip_as = 0;
1306: for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1307: for (y = 0; y < exclseg->length; y++)
1308: if (srcseg->as[i] == exclseg->as[y])
1309: {
1310: skip_as = 1;
1311: // There's no sense in testing the rest of exclusion list, bail out.
1312: break;
1313: }
1314: if (!skip_as)
1315: newlen++;
1316: }
1317: /* newlen is now the number of ASns to copy */
1318: if (!newlen)
1319: continue;
1320:
1321: /* Actual copying. Allocate memory and iterate once more, performing filtering. */
1322: newseg = assegment_new (srcseg->type, newlen);
1323: for (i = 0; i < srcseg->length; i++)
1324: {
1325: skip_as = 0;
1326: for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next)
1327: for (y = 0; y < exclseg->length; y++)
1328: if (srcseg->as[i] == exclseg->as[y])
1329: {
1330: skip_as = 1;
1331: break;
1332: }
1333: if (skip_as)
1334: continue;
1335: newseg->as[done++] = srcseg->as[i];
1336: }
1337: /* At his point newlen must be equal to done, and both must be positive. Append
1338: * the filtered segment to the gross result. */
1339: if (!lastseg)
1340: newpath->segments = newseg;
1341: else
1342: lastseg->next = newseg;
1343: lastseg = newseg;
1344: }
1345: aspath_str_update (newpath);
1346: /* We are happy returning even an empty AS_PATH, because the administrator
1347: * might expect this very behaviour. There's a mean to avoid this, if necessary,
1348: * by having a match rule against certain AS_PATH regexps in the route-map index.
1349: */
1350: aspath_free (source);
1351: return newpath;
1352: }
1353:
1354: /* Add specified AS to the leftmost of aspath. */
1355: static struct aspath *
1356: aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type)
1357: {
1358: struct assegment *assegment = aspath->segments;
1359:
1360: /* In case of empty aspath. */
1361: if (assegment == NULL || assegment->length == 0)
1362: {
1363: aspath->segments = assegment_new (type, 1);
1364: aspath->segments->as[0] = asno;
1365:
1366: if (assegment)
1367: assegment_free (assegment);
1368:
1369: return aspath;
1370: }
1371:
1372: if (assegment->type == type)
1373: aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1);
1374: else
1375: {
1376: /* create new segment
1377: * push it onto head of aspath's segment chain
1378: */
1379: struct assegment *newsegment;
1380:
1381: newsegment = assegment_new (type, 1);
1382: newsegment->as[0] = asno;
1383:
1384: newsegment->next = assegment;
1385: aspath->segments = newsegment;
1386: }
1387:
1388: return aspath;
1389: }
1390:
1391: /* Add specified AS to the leftmost of aspath. */
1392: struct aspath *
1393: aspath_add_seq (struct aspath *aspath, as_t asno)
1394: {
1395: return aspath_add_one_as (aspath, asno, AS_SEQUENCE);
1396: }
1397:
1398: /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1399: as2's leftmost AS is same return 1. */
1400: int
1401: aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2)
1402: {
1403: const struct assegment *seg1 = NULL;
1404: const struct assegment *seg2 = NULL;
1405:
1406: if (!(aspath1 && aspath2))
1407: return 0;
1408:
1409: seg1 = aspath1->segments;
1410: seg2 = aspath2->segments;
1411:
1412: /* find first non-confed segments for each */
1413: while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE)
1414: || (seg1->type == AS_CONFED_SET)))
1415: seg1 = seg1->next;
1416:
1417: while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE)
1418: || (seg2->type == AS_CONFED_SET)))
1419: seg2 = seg2->next;
1420:
1421: /* Check as1's */
1422: if (!(seg1 && seg2
1423: && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE)))
1424: return 0;
1425:
1426: if (seg1->as[0] == seg2->as[0])
1427: return 1;
1428:
1429: return 0;
1430: }
1431:
1432: /* Truncate an aspath after a number of hops, and put the hops remaining
1433: * at the front of another aspath. Needed for AS4 compat.
1434: *
1435: * Returned aspath is a /new/ aspath, which should either by free'd or
1436: * interned by the caller, as desired.
1437: */
1438: struct aspath *
1439: aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path)
1440: {
1441: struct assegment *seg, *newseg, *prevseg = NULL;
1442: struct aspath *newpath = NULL, *mergedpath;
1443: int hops, cpasns = 0;
1444:
1445: if (!aspath)
1446: return NULL;
1447:
1448: seg = aspath->segments;
1449:
1450: /* CONFEDs should get reconciled too.. */
1451: hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath))
1452: - aspath_count_hops (as4path);
1453:
1454: if (hops < 0)
1455: {
1456: if (BGP_DEBUG (as4, AS4))
1457: zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH");
1458: /* Something's gone wrong. The RFC says we should now ignore AS4_PATH,
1459: * which is daft behaviour - it contains vital loop-detection
1460: * information which must have been removed from AS_PATH.
1461: */
1462: hops = aspath_count_hops (aspath);
1463: }
1464:
1465: if (!hops)
1466: return aspath_dup (as4path);
1467:
1468: if ( BGP_DEBUG(as4, AS4))
1469: zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now",
1470: aspath->str, as4path->str);
1471:
1472: while (seg && hops > 0)
1473: {
1474: switch (seg->type)
1475: {
1476: case AS_SET:
1477: case AS_CONFED_SET:
1478: hops--;
1479: cpasns = seg->length;
1480: break;
1481: case AS_CONFED_SEQUENCE:
1482: /* Should never split a confed-sequence, if hop-count
1483: * suggests we must then something's gone wrong somewhere.
1484: *
1485: * Most important goal is to preserve AS_PATHs prime function
1486: * as loop-detector, so we fudge the numbers so that the entire
1487: * confed-sequence is merged in.
1488: */
1489: if (hops < seg->length)
1490: {
1491: if (BGP_DEBUG (as4, AS4))
1492: zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls"
1493: " across 2/4 ASN boundary somewhere, broken..");
1494: hops = seg->length;
1495: }
1496: case AS_SEQUENCE:
1497: cpasns = MIN(seg->length, hops);
1498: hops -= seg->length;
1499: }
1500:
1501: assert (cpasns <= seg->length);
1502:
1503: newseg = assegment_new (seg->type, 0);
1504: newseg = assegment_append_asns (newseg, seg->as, cpasns);
1505:
1506: if (!newpath)
1507: {
1508: newpath = aspath_new ();
1509: newpath->segments = newseg;
1510: }
1511: else
1512: prevseg->next = newseg;
1513:
1514: prevseg = newseg;
1515: seg = seg->next;
1516: }
1517:
1518: /* We may be able to join some segments here, and we must
1519: * do this because... we want normalised aspaths in out hash
1520: * and we do not want to stumble in aspath_put.
1521: */
1522: mergedpath = aspath_merge (newpath, aspath_dup(as4path));
1523: aspath_free (newpath);
1524: mergedpath->segments = assegment_normalise (mergedpath->segments);
1525: aspath_str_update (mergedpath);
1526:
1527: if ( BGP_DEBUG(as4, AS4))
1528: zlog_debug ("[AS4] result of synthesizing is %s",
1529: mergedpath->str);
1530:
1531: return mergedpath;
1532: }
1533:
1534: /* Compare leftmost AS value for MED check. If as1's leftmost AS and
1535: as2's leftmost AS is same return 1. (confederation as-path
1536: only). */
1537: int
1538: aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2)
1539: {
1540: if (! (aspath1 && aspath2) )
1541: return 0;
1542:
1543: if ( !(aspath1->segments && aspath2->segments) )
1544: return 0;
1545:
1546: if ( (aspath1->segments->type != AS_CONFED_SEQUENCE)
1547: || (aspath2->segments->type != AS_CONFED_SEQUENCE) )
1548: return 0;
1549:
1550: if (aspath1->segments->as[0] == aspath2->segments->as[0])
1551: return 1;
1552:
1553: return 0;
1554: }
1555:
1556: /* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath.
1557: * See RFC3065, 6.1 c1 */
1558: struct aspath *
1559: aspath_delete_confed_seq (struct aspath *aspath)
1560: {
1561: struct assegment *seg;
1562:
1563: if (!(aspath && aspath->segments))
1564: return aspath;
1565:
1566: seg = aspath->segments;
1567:
1568: /* "if the first path segment of the AS_PATH is
1569: * of type AS_CONFED_SEQUENCE,"
1570: */
1571: if (aspath->segments->type != AS_CONFED_SEQUENCE)
1572: return aspath;
1573:
1574: /* "... that segment and any immediately following segments
1575: * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed
1576: * from the AS_PATH attribute,"
1577: */
1578: while (seg &&
1579: (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET))
1580: {
1581: aspath->segments = seg->next;
1582: assegment_free (seg);
1583: seg = aspath->segments;
1584: }
1585: aspath_str_update (aspath);
1586: return aspath;
1587: }
1588:
1589: /* Add new AS number to the leftmost part of the aspath as
1590: AS_CONFED_SEQUENCE. */
1591: struct aspath*
1592: aspath_add_confed_seq (struct aspath *aspath, as_t asno)
1593: {
1594: return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE);
1595: }
1596:
1597: /* Add new as value to as path structure. */
1598: static void
1599: aspath_as_add (struct aspath *as, as_t asno)
1600: {
1601: struct assegment *seg = as->segments;
1602:
1603: if (!seg)
1604: return;
1605:
1606: /* Last segment search procedure. */
1607: while (seg->next)
1608: seg = seg->next;
1609:
1610: assegment_append_asns (seg, &asno, 1);
1611: }
1612:
1613: /* Add new as segment to the as path. */
1614: static void
1615: aspath_segment_add (struct aspath *as, int type)
1616: {
1617: struct assegment *seg = as->segments;
1618: struct assegment *new = assegment_new (type, 0);
1619:
1620: if (seg)
1621: {
1622: while (seg->next)
1623: seg = seg->next;
1624: seg->next = new;
1625: }
1626: else
1627: as->segments = new;
1628: }
1629:
1630: struct aspath *
1631: aspath_empty (void)
1632: {
1633: return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */
1634: }
1635:
1636: struct aspath *
1637: aspath_empty_get (void)
1638: {
1639: struct aspath *aspath;
1640:
1641: aspath = aspath_new ();
1642: aspath->str = aspath_make_str_count (aspath);
1643: return aspath;
1644: }
1645:
1646: unsigned long
1647: aspath_count (void)
1648: {
1649: return ashash->count;
1650: }
1651:
1652: /*
1653: Theoretically, one as path can have:
1654:
1655: One BGP packet size should be less than 4096.
1656: One BGP attribute size should be less than 4096 - BGP header size.
1657: One BGP aspath size should be less than 4096 - BGP header size -
1658: BGP mandantry attribute size.
1659: */
1660:
1661: /* AS path string lexical token enum. */
1662: enum as_token
1663: {
1664: as_token_asval,
1665: as_token_set_start,
1666: as_token_set_end,
1667: as_token_confed_seq_start,
1668: as_token_confed_seq_end,
1669: as_token_confed_set_start,
1670: as_token_confed_set_end,
1671: as_token_unknown
1672: };
1673:
1674: /* Return next token and point for string parse. */
1675: static const char *
1676: aspath_gettoken (const char *buf, enum as_token *token, u_long *asno)
1677: {
1678: const char *p = buf;
1679:
1680: /* Skip seperators (space for sequences, ',' for sets). */
1681: while (isspace ((int) *p) || *p == ',')
1682: p++;
1683:
1684: /* Check the end of the string and type specify characters
1685: (e.g. {}()). */
1686: switch (*p)
1687: {
1688: case '\0':
1689: return NULL;
1690: case '{':
1691: *token = as_token_set_start;
1692: p++;
1693: return p;
1694: case '}':
1695: *token = as_token_set_end;
1696: p++;
1697: return p;
1698: case '(':
1699: *token = as_token_confed_seq_start;
1700: p++;
1701: return p;
1702: case ')':
1703: *token = as_token_confed_seq_end;
1704: p++;
1705: return p;
1706: case '[':
1707: *token = as_token_confed_set_start;
1708: p++;
1709: return p;
1710: case ']':
1711: *token = as_token_confed_set_end;
1712: p++;
1713: return p;
1714: }
1715:
1716: /* Check actual AS value. */
1717: if (isdigit ((int) *p))
1718: {
1719: as_t asval;
1720:
1721: *token = as_token_asval;
1722: asval = (*p - '0');
1723: p++;
1724:
1725: while (isdigit ((int) *p))
1726: {
1727: asval *= 10;
1728: asval += (*p - '0');
1729: p++;
1730: }
1731: *asno = asval;
1732: return p;
1733: }
1734:
1735: /* There is no match then return unknown token. */
1736: *token = as_token_unknown;
1737: return p++;
1738: }
1739:
1740: struct aspath *
1741: aspath_str2aspath (const char *str)
1742: {
1743: enum as_token token = as_token_unknown;
1744: u_short as_type;
1745: u_long asno = 0;
1746: struct aspath *aspath;
1747: int needtype;
1748:
1749: aspath = aspath_new ();
1750:
1751: /* We start default type as AS_SEQUENCE. */
1752: as_type = AS_SEQUENCE;
1753: needtype = 1;
1754:
1755: while ((str = aspath_gettoken (str, &token, &asno)) != NULL)
1756: {
1757: switch (token)
1758: {
1759: case as_token_asval:
1760: if (needtype)
1761: {
1762: aspath_segment_add (aspath, as_type);
1763: needtype = 0;
1764: }
1765: aspath_as_add (aspath, asno);
1766: break;
1767: case as_token_set_start:
1768: as_type = AS_SET;
1769: aspath_segment_add (aspath, as_type);
1770: needtype = 0;
1771: break;
1772: case as_token_set_end:
1773: as_type = AS_SEQUENCE;
1774: needtype = 1;
1775: break;
1776: case as_token_confed_seq_start:
1777: as_type = AS_CONFED_SEQUENCE;
1778: aspath_segment_add (aspath, as_type);
1779: needtype = 0;
1780: break;
1781: case as_token_confed_seq_end:
1782: as_type = AS_SEQUENCE;
1783: needtype = 1;
1784: break;
1785: case as_token_confed_set_start:
1786: as_type = AS_CONFED_SET;
1787: aspath_segment_add (aspath, as_type);
1788: needtype = 0;
1789: break;
1790: case as_token_confed_set_end:
1791: as_type = AS_SEQUENCE;
1792: needtype = 1;
1793: break;
1794: case as_token_unknown:
1795: default:
1796: aspath_free (aspath);
1797: return NULL;
1798: }
1799: }
1800:
1801: aspath->str = aspath_make_str_count (aspath);
1802:
1803: return aspath;
1804: }
1805:
1806: /* Make hash value by raw aspath data. */
1807: unsigned int
1808: aspath_key_make (void *p)
1809: {
1810: struct aspath * aspath = (struct aspath *) p;
1811: unsigned int key = 0;
1812:
1813: if (!aspath->str)
1814: aspath_str_update (aspath);
1815:
1816: key = jhash (aspath->str, strlen(aspath->str), 2334325);
1817:
1818: return key;
1819: }
1820:
1821: /* If two aspath have same value then return 1 else return 0 */
1822: static int
1823: aspath_cmp (const void *arg1, const void *arg2)
1824: {
1825: const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
1826: const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
1827:
1828: while (seg1 || seg2)
1829: {
1830: int i;
1831: if ((!seg1 && seg2) || (seg1 && !seg2))
1832: return 0;
1833: if (seg1->type != seg2->type)
1834: return 0;
1835: if (seg1->length != seg2->length)
1836: return 0;
1837: for (i = 0; i < seg1->length; i++)
1838: if (seg1->as[i] != seg2->as[i])
1839: return 0;
1840: seg1 = seg1->next;
1841: seg2 = seg2->next;
1842: }
1843: return 1;
1844: }
1845:
1846: /* AS path hash initialize. */
1847: void
1848: aspath_init (void)
1849: {
1850: ashash = hash_create_size (32767, aspath_key_make, aspath_cmp);
1851: }
1852:
1853: void
1854: aspath_finish (void)
1855: {
1856: hash_free (ashash);
1857: ashash = NULL;
1858:
1859: if (snmp_stream)
1860: stream_free (snmp_stream);
1861: }
1862:
1863: /* return and as path value */
1864: const char *
1865: aspath_print (struct aspath *as)
1866: {
1867: return (as ? as->str : NULL);
1868: }
1869:
1870: /* Printing functions */
1871: /* Feed the AS_PATH to the vty; the suffix string follows it only in case
1872: * AS_PATH wasn't empty.
1873: */
1874: void
1875: aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix)
1876: {
1877: assert (format);
1878: vty_out (vty, format, as->str);
1879: if (strlen (as->str) && strlen (suffix))
1880: vty_out (vty, "%s", suffix);
1881: }
1882:
1883: static void
1884: aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty)
1885: {
1886: struct aspath *as;
1887:
1888: as = (struct aspath *) backet->data;
1889:
1890: vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt);
1891: vty_out (vty, "%s%s", as->str, VTY_NEWLINE);
1892: }
1893:
1894: /* Print all aspath and hash information. This function is used from
1895: `show ip bgp paths' command. */
1896: void
1897: aspath_print_all_vty (struct vty *vty)
1898: {
1899: hash_iterate (ashash,
1900: (void (*) (struct hash_backet *, void *))
1901: aspath_show_all_iterator,
1902: vty);
1903: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>