Annotation of embedaddon/quagga/bgpd/bgp_attr.c, revision 1.1.1.3
1.1 misho 1: /* BGP attributes management routines.
2: Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3:
4: This file is part of GNU Zebra.
5:
6: GNU Zebra is free software; you can redistribute it and/or modify it
7: under the terms of the GNU General Public License as published by the
8: Free Software Foundation; either version 2, or (at your option) any
9: later version.
10:
11: GNU Zebra is distributed in the hope that it will be useful, but
12: WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU Zebra; see the file COPYING. If not, write to the Free
18: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19: 02111-1307, USA. */
20:
21: #include <zebra.h>
22:
23: #include "linklist.h"
24: #include "prefix.h"
25: #include "memory.h"
26: #include "vector.h"
27: #include "vty.h"
28: #include "stream.h"
29: #include "log.h"
30: #include "hash.h"
31: #include "jhash.h"
32:
33: #include "bgpd/bgpd.h"
34: #include "bgpd/bgp_attr.h"
35: #include "bgpd/bgp_route.h"
36: #include "bgpd/bgp_aspath.h"
37: #include "bgpd/bgp_community.h"
38: #include "bgpd/bgp_debug.h"
39: #include "bgpd/bgp_packet.h"
40: #include "bgpd/bgp_ecommunity.h"
41:
42: /* Attribute strings for logging. */
43: static const struct message attr_str [] =
44: {
45: { BGP_ATTR_ORIGIN, "ORIGIN" },
46: { BGP_ATTR_AS_PATH, "AS_PATH" },
47: { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48: { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49: { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50: { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51: { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52: { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53: { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
1.1.1.2 misho 54: { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
1.1 misho 55: { BGP_ATTR_DPA, "DPA" },
56: { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57: { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58: { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59: { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
60: { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61: { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62: { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63: { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
64: };
1.1.1.3 ! misho 65: static const int attr_str_max = array_size(attr_str);
1.1.1.2 misho 66:
67: static const struct message attr_flag_str[] =
68: {
69: { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
70: { BGP_ATTR_FLAG_TRANS, "Transitive" },
71: { BGP_ATTR_FLAG_PARTIAL, "Partial" },
72: /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
73: { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
74: };
1.1.1.3 ! misho 75: static const size_t attr_flag_str_max = array_size(attr_flag_str);
1.1 misho 76:
77: static struct hash *cluster_hash;
78:
79: static void *
80: cluster_hash_alloc (void *p)
81: {
82: struct cluster_list * val = (struct cluster_list *) p;
83: struct cluster_list *cluster;
84:
85: cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
86: cluster->length = val->length;
87:
88: if (cluster->length)
89: {
90: cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
91: memcpy (cluster->list, val->list, val->length);
92: }
93: else
94: cluster->list = NULL;
95:
96: cluster->refcnt = 0;
97:
98: return cluster;
99: }
100:
101: /* Cluster list related functions. */
102: static struct cluster_list *
103: cluster_parse (struct in_addr * pnt, int length)
104: {
105: struct cluster_list tmp;
106: struct cluster_list *cluster;
107:
108: tmp.length = length;
109: tmp.list = pnt;
110:
111: cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
112: cluster->refcnt++;
113: return cluster;
114: }
115:
116: int
117: cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
118: {
119: int i;
120:
121: for (i = 0; i < cluster->length / 4; i++)
122: if (cluster->list[i].s_addr == originator.s_addr)
123: return 1;
124: return 0;
125: }
126:
127: static unsigned int
128: cluster_hash_key_make (void *p)
129: {
130: const struct cluster_list *cluster = p;
131:
132: return jhash(cluster->list, cluster->length, 0);
133: }
134:
135: static int
136: cluster_hash_cmp (const void *p1, const void *p2)
137: {
138: const struct cluster_list * cluster1 = p1;
139: const struct cluster_list * cluster2 = p2;
140:
141: return (cluster1->length == cluster2->length &&
142: memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
143: }
144:
145: static void
146: cluster_free (struct cluster_list *cluster)
147: {
148: if (cluster->list)
149: XFREE (MTYPE_CLUSTER_VAL, cluster->list);
150: XFREE (MTYPE_CLUSTER, cluster);
151: }
152:
153: #if 0
154: static struct cluster_list *
155: cluster_dup (struct cluster_list *cluster)
156: {
157: struct cluster_list *new;
158:
159: new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
160: new->length = cluster->length;
161:
162: if (cluster->length)
163: {
164: new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
165: memcpy (new->list, cluster->list, cluster->length);
166: }
167: else
168: new->list = NULL;
169:
170: return new;
171: }
172: #endif
173:
174: static struct cluster_list *
175: cluster_intern (struct cluster_list *cluster)
176: {
177: struct cluster_list *find;
178:
179: find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
180: find->refcnt++;
181:
182: return find;
183: }
184:
185: void
186: cluster_unintern (struct cluster_list *cluster)
187: {
188: if (cluster->refcnt)
189: cluster->refcnt--;
190:
191: if (cluster->refcnt == 0)
192: {
1.1.1.2 misho 193: hash_release (cluster_hash, cluster);
1.1 misho 194: cluster_free (cluster);
195: }
196: }
197:
198: static void
199: cluster_init (void)
200: {
201: cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202: }
203:
204: static void
205: cluster_finish (void)
206: {
207: hash_free (cluster_hash);
208: cluster_hash = NULL;
209: }
210:
211: /* Unknown transit attribute. */
212: static struct hash *transit_hash;
213:
214: static void
215: transit_free (struct transit *transit)
216: {
217: if (transit->val)
218: XFREE (MTYPE_TRANSIT_VAL, transit->val);
219: XFREE (MTYPE_TRANSIT, transit);
220: }
221:
222:
223: static void *
224: transit_hash_alloc (void *p)
225: {
226: /* Transit structure is already allocated. */
227: return p;
228: }
229:
230: static struct transit *
231: transit_intern (struct transit *transit)
232: {
233: struct transit *find;
234:
235: find = hash_get (transit_hash, transit, transit_hash_alloc);
236: if (find != transit)
237: transit_free (transit);
238: find->refcnt++;
239:
240: return find;
241: }
242:
243: void
244: transit_unintern (struct transit *transit)
245: {
246: if (transit->refcnt)
247: transit->refcnt--;
248:
249: if (transit->refcnt == 0)
250: {
1.1.1.2 misho 251: hash_release (transit_hash, transit);
1.1 misho 252: transit_free (transit);
253: }
254: }
255:
256: static unsigned int
257: transit_hash_key_make (void *p)
258: {
259: const struct transit * transit = p;
260:
261: return jhash(transit->val, transit->length, 0);
262: }
263:
264: static int
265: transit_hash_cmp (const void *p1, const void *p2)
266: {
267: const struct transit * transit1 = p1;
268: const struct transit * transit2 = p2;
269:
270: return (transit1->length == transit2->length &&
271: memcmp (transit1->val, transit2->val, transit1->length) == 0);
272: }
273:
274: static void
275: transit_init (void)
276: {
277: transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
278: }
279:
280: static void
281: transit_finish (void)
282: {
283: hash_free (transit_hash);
284: transit_hash = NULL;
285: }
286:
287: /* Attribute hash routines. */
288: static struct hash *attrhash;
289:
290: static struct attr_extra *
291: bgp_attr_extra_new (void)
292: {
293: return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
294: }
295:
296: void
297: bgp_attr_extra_free (struct attr *attr)
298: {
299: if (attr->extra)
300: {
301: XFREE (MTYPE_ATTR_EXTRA, attr->extra);
302: attr->extra = NULL;
303: }
304: }
305:
306: struct attr_extra *
307: bgp_attr_extra_get (struct attr *attr)
308: {
309: if (!attr->extra)
310: attr->extra = bgp_attr_extra_new();
311: return attr->extra;
312: }
313:
314: /* Shallow copy of an attribute
315: * Though, not so shallow that it doesn't copy the contents
316: * of the attr_extra pointed to by 'extra'
317: */
318: void
319: bgp_attr_dup (struct attr *new, struct attr *orig)
320: {
1.1.1.3 ! misho 321: struct attr_extra *extra = new->extra;
! 322:
1.1 misho 323: *new = *orig;
1.1.1.3 ! misho 324: /* if caller provided attr_extra space, use it in any case.
! 325: *
! 326: * This is neccesary even if orig->extra equals NULL, because otherwise
! 327: * memory may be later allocated on the heap by bgp_attr_extra_get.
! 328: *
! 329: * That memory would eventually be leaked, because the caller must not
! 330: * call bgp_attr_extra_free if he provided attr_extra on the stack.
! 331: */
! 332: if (extra)
! 333: {
! 334: new->extra = extra;
! 335: memset(new->extra, 0, sizeof(struct attr_extra));
! 336: if (orig->extra)
! 337: *new->extra = *orig->extra;
! 338: }
! 339: else if (orig->extra)
1.1 misho 340: {
341: new->extra = bgp_attr_extra_new();
342: *new->extra = *orig->extra;
343: }
344: }
345:
346: unsigned long int
347: attr_count (void)
348: {
349: return attrhash->count;
350: }
351:
352: unsigned long int
353: attr_unknown_count (void)
354: {
355: return transit_hash->count;
356: }
357:
358: unsigned int
359: attrhash_key_make (void *p)
360: {
1.1.1.3 ! misho 361: const struct attr *attr = (struct attr *) p;
! 362: const struct attr_extra *extra = attr->extra;
1.1 misho 363: uint32_t key = 0;
364: #define MIX(val) key = jhash_1word(val, key)
365:
366: MIX(attr->origin);
367: MIX(attr->nexthop.s_addr);
368: MIX(attr->med);
369: MIX(attr->local_pref);
370:
371: key += attr->origin;
372: key += attr->nexthop.s_addr;
373: key += attr->med;
374: key += attr->local_pref;
375:
1.1.1.3 ! misho 376: if (extra)
1.1 misho 377: {
1.1.1.3 ! misho 378: MIX(extra->aggregator_as);
! 379: MIX(extra->aggregator_addr.s_addr);
! 380: MIX(extra->weight);
! 381: MIX(extra->mp_nexthop_global_in.s_addr);
1.1 misho 382: }
383:
384: if (attr->aspath)
385: MIX(aspath_key_make (attr->aspath));
386: if (attr->community)
387: MIX(community_hash_make (attr->community));
388:
1.1.1.3 ! misho 389: if (extra)
1.1 misho 390: {
1.1.1.3 ! misho 391: if (extra->ecommunity)
! 392: MIX(ecommunity_hash_make (extra->ecommunity));
! 393: if (extra->cluster)
! 394: MIX(cluster_hash_key_make (extra->cluster));
! 395: if (extra->transit)
! 396: MIX(transit_hash_key_make (extra->transit));
1.1 misho 397:
398: #ifdef HAVE_IPV6
1.1.1.3 ! misho 399: MIX(extra->mp_nexthop_len);
! 400: key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
! 401: key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
1.1 misho 402: #endif /* HAVE_IPV6 */
403: }
404:
405: return key;
406: }
407:
408: int
409: attrhash_cmp (const void *p1, const void *p2)
410: {
411: const struct attr * attr1 = p1;
412: const struct attr * attr2 = p2;
413:
414: if (attr1->flag == attr2->flag
415: && attr1->origin == attr2->origin
416: && attr1->nexthop.s_addr == attr2->nexthop.s_addr
417: && attr1->aspath == attr2->aspath
418: && attr1->community == attr2->community
419: && attr1->med == attr2->med
420: && attr1->local_pref == attr2->local_pref)
421: {
422: const struct attr_extra *ae1 = attr1->extra;
423: const struct attr_extra *ae2 = attr2->extra;
424:
425: if (ae1 && ae2
426: && ae1->aggregator_as == ae2->aggregator_as
427: && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
428: && ae1->weight == ae2->weight
429: #ifdef HAVE_IPV6
430: && ae1->mp_nexthop_len == ae2->mp_nexthop_len
431: && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
432: && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
433: #endif /* HAVE_IPV6 */
434: && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
435: && ae1->ecommunity == ae2->ecommunity
436: && ae1->cluster == ae2->cluster
437: && ae1->transit == ae2->transit)
438: return 1;
439: else if (ae1 || ae2)
440: return 0;
441: /* neither attribute has extra attributes, so they're same */
442: return 1;
443: }
444: else
445: return 0;
446: }
447:
448: static void
449: attrhash_init (void)
450: {
451: attrhash = hash_create (attrhash_key_make, attrhash_cmp);
452: }
453:
454: static void
455: attrhash_finish (void)
456: {
457: hash_free (attrhash);
458: attrhash = NULL;
459: }
460:
461: static void
462: attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
463: {
464: struct attr *attr = backet->data;
465:
466: vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
467: inet_ntoa (attr->nexthop), VTY_NEWLINE);
468: }
469:
470: void
471: attr_show_all (struct vty *vty)
472: {
473: hash_iterate (attrhash,
474: (void (*)(struct hash_backet *, void *))
475: attr_show_all_iterator,
476: vty);
477: }
478:
479: static void *
480: bgp_attr_hash_alloc (void *p)
481: {
482: struct attr * val = (struct attr *) p;
483: struct attr *attr;
484:
485: attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
486: *attr = *val;
487: if (val->extra)
488: {
489: attr->extra = bgp_attr_extra_new ();
490: *attr->extra = *val->extra;
491: }
492: attr->refcnt = 0;
493: return attr;
494: }
495:
496: /* Internet argument attribute. */
497: struct attr *
498: bgp_attr_intern (struct attr *attr)
499: {
500: struct attr *find;
501:
502: /* Intern referenced strucutre. */
503: if (attr->aspath)
504: {
505: if (! attr->aspath->refcnt)
506: attr->aspath = aspath_intern (attr->aspath);
507: else
508: attr->aspath->refcnt++;
509: }
510: if (attr->community)
511: {
512: if (! attr->community->refcnt)
513: attr->community = community_intern (attr->community);
514: else
515: attr->community->refcnt++;
516: }
517: if (attr->extra)
518: {
519: struct attr_extra *attre = attr->extra;
520:
521: if (attre->ecommunity)
522: {
523: if (! attre->ecommunity->refcnt)
524: attre->ecommunity = ecommunity_intern (attre->ecommunity);
525: else
526: attre->ecommunity->refcnt++;
527:
528: }
529: if (attre->cluster)
530: {
531: if (! attre->cluster->refcnt)
532: attre->cluster = cluster_intern (attre->cluster);
533: else
534: attre->cluster->refcnt++;
535: }
536: if (attre->transit)
537: {
538: if (! attre->transit->refcnt)
539: attre->transit = transit_intern (attre->transit);
540: else
541: attre->transit->refcnt++;
542: }
543: }
544:
545: find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
546: find->refcnt++;
547:
548: return find;
549: }
550:
551:
552: /* Make network statement's attribute. */
553: struct attr *
554: bgp_attr_default_set (struct attr *attr, u_char origin)
555: {
556: memset (attr, 0, sizeof (struct attr));
557: bgp_attr_extra_get (attr);
558:
559: attr->origin = origin;
560: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
561: attr->aspath = aspath_empty ();
562: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
563: attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
564: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
565: #ifdef HAVE_IPV6
566: attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
567: #endif
568:
569: return attr;
570: }
571:
572:
573: /* Make network statement's attribute. */
574: struct attr *
575: bgp_attr_default_intern (u_char origin)
576: {
577: struct attr attr;
578: struct attr *new;
1.1.1.3 ! misho 579:
1.1 misho 580: bgp_attr_default_set(&attr, origin);
581:
582: new = bgp_attr_intern (&attr);
583: bgp_attr_extra_free (&attr);
584:
585: aspath_unintern (&new->aspath);
586: return new;
587: }
588:
589: struct attr *
590: bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
591: struct aspath *aspath,
592: struct community *community, int as_set)
593: {
594: struct attr attr;
595: struct attr *new;
1.1.1.3 ! misho 596: struct attr_extra attre;
1.1 misho 597:
598: memset (&attr, 0, sizeof (struct attr));
1.1.1.3 ! misho 599: memset (&attre, 0, sizeof (struct attr_extra));
! 600: attr.extra = &attre;
! 601:
1.1 misho 602: /* Origin attribute. */
603: attr.origin = origin;
604: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
605:
606: /* AS path attribute. */
607: if (aspath)
608: attr.aspath = aspath_intern (aspath);
609: else
610: attr.aspath = aspath_empty ();
611: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
612:
613: /* Next hop attribute. */
614: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
615:
616: if (community)
617: {
618: attr.community = community;
619: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
620: }
621:
1.1.1.3 ! misho 622: attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
1.1 misho 623: #ifdef HAVE_IPV6
1.1.1.3 ! misho 624: attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
1.1 misho 625: #endif
626: if (! as_set)
627: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
628: attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
629: if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
1.1.1.3 ! misho 630: attre.aggregator_as = bgp->confed_id;
1.1 misho 631: else
1.1.1.3 ! misho 632: attre.aggregator_as = bgp->as;
! 633: attre.aggregator_addr = bgp->router_id;
1.1 misho 634:
635: new = bgp_attr_intern (&attr);
1.1.1.3 ! misho 636:
1.1 misho 637: aspath_unintern (&new->aspath);
638: return new;
639: }
640:
641: /* Unintern just the sub-components of the attr, but not the attr */
642: void
643: bgp_attr_unintern_sub (struct attr *attr)
644: {
645: /* aspath refcount shoud be decrement. */
646: if (attr->aspath)
647: aspath_unintern (&attr->aspath);
648: UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
649:
650: if (attr->community)
651: community_unintern (&attr->community);
652: UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
653:
654: if (attr->extra)
655: {
656: if (attr->extra->ecommunity)
657: ecommunity_unintern (&attr->extra->ecommunity);
658: UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
659:
660: if (attr->extra->cluster)
661: cluster_unintern (attr->extra->cluster);
662: UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
663:
664: if (attr->extra->transit)
665: transit_unintern (attr->extra->transit);
666: }
667: }
668:
669: /* Free bgp attribute and aspath. */
670: void
1.1.1.3 ! misho 671: bgp_attr_unintern (struct attr **pattr)
1.1 misho 672: {
1.1.1.3 ! misho 673: struct attr *attr = *pattr;
1.1 misho 674: struct attr *ret;
675: struct attr tmp;
1.1.1.3 ! misho 676: struct attr_extra tmp_extra;
1.1 misho 677:
678: /* Decrement attribute reference. */
1.1.1.3 ! misho 679: attr->refcnt--;
1.1 misho 680:
1.1.1.3 ! misho 681: tmp = *attr;
1.1 misho 682:
1.1.1.3 ! misho 683: if (attr->extra)
1.1 misho 684: {
1.1.1.3 ! misho 685: tmp.extra = &tmp_extra;
! 686: memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
1.1 misho 687: }
688:
689: /* If reference becomes zero then free attribute object. */
1.1.1.3 ! misho 690: if (attr->refcnt == 0)
! 691: {
! 692: ret = hash_release (attrhash, attr);
1.1 misho 693: assert (ret != NULL);
1.1.1.3 ! misho 694: bgp_attr_extra_free (attr);
! 695: XFREE (MTYPE_ATTR, attr);
! 696: *pattr = NULL;
1.1 misho 697: }
698:
699: bgp_attr_unintern_sub (&tmp);
700: }
701:
702: void
703: bgp_attr_flush (struct attr *attr)
704: {
705: if (attr->aspath && ! attr->aspath->refcnt)
706: aspath_free (attr->aspath);
707: if (attr->community && ! attr->community->refcnt)
708: community_free (attr->community);
709: if (attr->extra)
710: {
711: struct attr_extra *attre = attr->extra;
712:
713: if (attre->ecommunity && ! attre->ecommunity->refcnt)
714: ecommunity_free (&attre->ecommunity);
715: if (attre->cluster && ! attre->cluster->refcnt)
716: cluster_free (attre->cluster);
717: if (attre->transit && ! attre->transit->refcnt)
718: transit_free (attre->transit);
719: }
720: }
721:
722: /* Implement draft-scudder-idr-optional-transitive behaviour and
723: * avoid resetting sessions for malformed attributes which are
724: * are partial/optional and hence where the error likely was not
725: * introduced by the sending neighbour.
726: */
727: static bgp_attr_parse_ret_t
1.1.1.2 misho 728: bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
729: bgp_size_t length)
1.1 misho 730: {
1.1.1.2 misho 731: struct peer *const peer = args->peer;
732: const u_int8_t flags = args->flags;
733: /* startp and length must be special-cased, as whether or not to
734: * send the attribute data with the NOTIFY depends on the error,
735: * the caller therefore signals this with the seperate length argument
736: */
737: u_char *notify_datap = (length > 0 ? args->startp : NULL);
738:
1.1 misho 739: /* Only relax error handling for eBGP peers */
1.1.1.3 ! misho 740: if (peer->sort != BGP_PEER_EBGP)
1.1 misho 741: {
742: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
1.1.1.2 misho 743: notify_datap, length);
1.1 misho 744: return BGP_ATTR_PARSE_ERROR;
745:
746: }
747:
1.1.1.2 misho 748: /* Adjust the stream getp to the end of the attribute, in case we can
749: * still proceed but the caller hasn't read all the attribute.
750: */
751: stream_set_getp (BGP_INPUT (peer),
752: (args->startp - STREAM_DATA (BGP_INPUT (peer)))
753: + args->total);
754:
755: switch (args->type) {
756: /* where an attribute is relatively inconsequential, e.g. it does not
757: * affect route selection, and can be safely ignored, then any such
758: * attributes which are malformed should just be ignored and the route
759: * processed as normal.
1.1 misho 760: */
761: case BGP_ATTR_AS4_AGGREGATOR:
762: case BGP_ATTR_AGGREGATOR:
763: case BGP_ATTR_ATOMIC_AGGREGATE:
764: return BGP_ATTR_PARSE_PROCEED;
765:
766: /* Core attributes, particularly ones which may influence route
1.1.1.2 misho 767: * selection, should always cause session resets
1.1 misho 768: */
769: case BGP_ATTR_ORIGIN:
770: case BGP_ATTR_AS_PATH:
771: case BGP_ATTR_NEXT_HOP:
772: case BGP_ATTR_MULTI_EXIT_DISC:
773: case BGP_ATTR_LOCAL_PREF:
774: case BGP_ATTR_COMMUNITIES:
775: case BGP_ATTR_ORIGINATOR_ID:
776: case BGP_ATTR_CLUSTER_LIST:
777: case BGP_ATTR_MP_REACH_NLRI:
778: case BGP_ATTR_MP_UNREACH_NLRI:
779: case BGP_ATTR_EXT_COMMUNITIES:
780: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
1.1.1.2 misho 781: notify_datap, length);
1.1 misho 782: return BGP_ATTR_PARSE_ERROR;
783: }
784:
785: /* Partial optional attributes that are malformed should not cause
786: * the whole session to be reset. Instead treat it as a withdrawal
787: * of the routes, if possible.
788: */
1.1.1.2 misho 789: if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
790: && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
791: && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
1.1 misho 792: return BGP_ATTR_PARSE_WITHDRAW;
793:
794: /* default to reset */
795: return BGP_ATTR_PARSE_ERROR;
796: }
797:
1.1.1.2 misho 798: /* Find out what is wrong with the path attribute flag bits and log the error.
799: "Flag bits" here stand for Optional, Transitive and Partial, but not for
800: Extended Length. Checking O/T/P bits at once implies, that the attribute
801: being diagnosed is defined by RFC as either a "well-known" or an "optional,
802: non-transitive" attribute. */
803: static void
804: bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
805: u_int8_t desired_flags /* how RFC says it must be */
806: )
807: {
808: u_char seen = 0, i;
809: u_char real_flags = args->flags;
810: const u_int8_t attr_code = args->type;
811:
812: desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
813: real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
814: for (i = 0; i <= 2; i++) /* O,T,P, but not E */
815: if
816: (
817: CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
818: CHECK_FLAG (real_flags, attr_flag_str[i].key)
819: )
820: {
821: zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
822: LOOKUP (attr_str, attr_code),
823: CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
824: attr_flag_str[i].str);
825: seen = 1;
826: }
827: if (!seen)
828: {
829: zlog (args->peer->log, LOG_DEBUG,
830: "Strange, %s called for attr %s, but no problem found with flags"
831: " (real flags 0x%x, desired 0x%x)",
832: __func__, LOOKUP (attr_str, attr_code),
833: real_flags, desired_flags);
834: }
835: }
836:
837: /* Required flags for attributes. EXTLEN will be masked off when testing,
838: * as will PARTIAL for optional+transitive attributes.
839: */
840: const u_int8_t attr_flags_values [] = {
841: [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
842: [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
843: [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
844: [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
845: [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
846: [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
847: [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
848: [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
849: [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
850: [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
851: [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
852: [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
853: [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
854: [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
855: [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
856: };
857: static const size_t attr_flags_values_max =
858: sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
1.1 misho 859:
1.1.1.2 misho 860: static int
861: bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
862: {
863: u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
864: const u_int8_t flags = args->flags;
865: const u_int8_t attr_code = args->type;
866: struct peer *const peer = args->peer;
867:
868: /* there may be attributes we don't know about */
869: if (attr_code > attr_flags_values_max)
870: return 0;
871: if (attr_flags_values[attr_code] == 0)
872: return 0;
873:
874: /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
875: * 1."
876: */
877: if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
878: && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
1.1 misho 879: {
1.1.1.2 misho 880: zlog (peer->log, LOG_ERR,
881: "%s well-known attributes must have transitive flag set (%x)",
882: LOOKUP (attr_str, attr_code), flags);
883: return 1;
884: }
885:
886: /* "For well-known attributes and for optional non-transitive attributes,
887: * the Partial bit MUST be set to 0."
888: */
889: if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
890: {
891: if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
892: {
893: zlog (peer->log, LOG_ERR,
894: "%s well-known attribute "
895: "must NOT have the partial flag set (%x)",
896: LOOKUP (attr_str, attr_code), flags);
897: return 1;
898: }
899: if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
900: && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
901: {
902: zlog (peer->log, LOG_ERR,
903: "%s optional + transitive attribute "
904: "must NOT have the partial flag set (%x)",
905: LOOKUP (attr_str, attr_code), flags);
906: return 1;
907: }
1.1 misho 908: }
1.1.1.2 misho 909:
910: /* Optional transitive attributes may go through speakers that don't
911: * reocgnise them and set the Partial bit.
912: */
913: if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
914: && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
915: SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
916:
917: if ((flags & ~mask)
918: == attr_flags_values[attr_code])
919: return 0;
920:
921: bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
922: return 1;
923: }
1.1 misho 924:
1.1.1.2 misho 925: /* Get origin attribute of the update message. */
926: static bgp_attr_parse_ret_t
927: bgp_attr_origin (struct bgp_attr_parser_args *args)
928: {
929: struct peer *const peer = args->peer;
930: struct attr *const attr = args->attr;
931: const bgp_size_t length = args->length;
932:
1.1 misho 933: /* If any recognized attribute has Attribute Length that conflicts
934: with the expected length (based on the attribute type code), then
935: the Error Subcode is set to Attribute Length Error. The Data
936: field contains the erroneous attribute (type, length and
937: value). */
938: if (length != 1)
939: {
940: zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
941: length);
1.1.1.2 misho 942: return bgp_attr_malformed (args,
1.1 misho 943: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 944: args->total);
1.1 misho 945: }
946:
947: /* Fetch origin attribute. */
948: attr->origin = stream_getc (BGP_INPUT (peer));
949:
950: /* If the ORIGIN attribute has an undefined value, then the Error
951: Subcode is set to Invalid Origin Attribute. The Data field
952: contains the unrecognized attribute (type, length and value). */
953: if ((attr->origin != BGP_ORIGIN_IGP)
954: && (attr->origin != BGP_ORIGIN_EGP)
955: && (attr->origin != BGP_ORIGIN_INCOMPLETE))
956: {
957: zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
958: attr->origin);
1.1.1.2 misho 959: return bgp_attr_malformed (args,
1.1 misho 960: BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
1.1.1.2 misho 961: args->total);
1.1 misho 962: }
963:
964: /* Set oring attribute flag. */
965: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
966:
967: return 0;
968: }
969:
970: /* Parse AS path information. This function is wrapper of
971: aspath_parse. */
972: static int
1.1.1.2 misho 973: bgp_attr_aspath (struct bgp_attr_parser_args *args)
1.1 misho 974: {
1.1.1.2 misho 975: struct attr *const attr = args->attr;
976: struct peer *const peer = args->peer;
977: const bgp_size_t length = args->length;
978:
1.1 misho 979: /*
980: * peer with AS4 => will get 4Byte ASnums
981: * otherwise, will get 16 Bit
982: */
983: attr->aspath = aspath_parse (peer->ibuf, length,
984: CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
985:
986: /* In case of IBGP, length will be zero. */
987: if (! attr->aspath)
988: {
989: zlog (peer->log, LOG_ERR,
990: "Malformed AS path from %s, length is %d",
991: peer->host, length);
1.1.1.2 misho 992: return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
1.1 misho 993: }
994:
995: /* Set aspath attribute flag. */
996: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
997:
998: return BGP_ATTR_PARSE_PROCEED;
999: }
1000:
1001: static bgp_attr_parse_ret_t
1.1.1.2 misho 1002: bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
1.1 misho 1003: {
1004: /* These checks were part of bgp_attr_aspath, but with
1005: * as4 we should to check aspath things when
1006: * aspath synthesizing with as4_path has already taken place.
1007: * Otherwise we check ASPATH and use the synthesized thing, and that is
1008: * not right.
1009: * So do the checks later, i.e. here
1010: */
1011: struct bgp *bgp = peer->bgp;
1012: struct aspath *aspath;
1013:
1014: /* Confederation sanity check. */
1.1.1.3 ! misho 1015: if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
! 1016: (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
1.1 misho 1017: {
1018: zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
1.1.1.2 misho 1019: bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1020: BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1021: return BGP_ATTR_PARSE_ERROR;
1.1 misho 1022: }
1023:
1024: /* First AS check for EBGP. */
1025: if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1026: {
1.1.1.3 ! misho 1027: if (peer->sort == BGP_PEER_EBGP
1.1 misho 1028: && ! aspath_firstas_check (attr->aspath, peer->as))
1029: {
1030: zlog (peer->log, LOG_ERR,
1031: "%s incorrect first AS (must be %u)", peer->host, peer->as);
1.1.1.2 misho 1032: bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1033: BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1034: return BGP_ATTR_PARSE_ERROR;
1.1 misho 1035: }
1036: }
1037:
1038: /* local-as prepend */
1039: if (peer->change_local_as &&
1040: ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1041: {
1042: aspath = aspath_dup (attr->aspath);
1043: aspath = aspath_add_seq (aspath, peer->change_local_as);
1044: aspath_unintern (&attr->aspath);
1045: attr->aspath = aspath_intern (aspath);
1046: }
1047:
1048: return BGP_ATTR_PARSE_PROCEED;
1049: }
1050:
1051: /* Parse AS4 path information. This function is another wrapper of
1052: aspath_parse. */
1053: static int
1.1.1.2 misho 1054: bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
1.1 misho 1055: {
1.1.1.2 misho 1056: struct peer *const peer = args->peer;
1057: struct attr *const attr = args->attr;
1058: const bgp_size_t length = args->length;
1059:
1.1 misho 1060: *as4_path = aspath_parse (peer->ibuf, length, 1);
1061:
1062: /* In case of IBGP, length will be zero. */
1063: if (!*as4_path)
1064: {
1065: zlog (peer->log, LOG_ERR,
1066: "Malformed AS4 path from %s, length is %d",
1067: peer->host, length);
1.1.1.2 misho 1068: return bgp_attr_malformed (args,
1.1 misho 1069: BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1.1.1.2 misho 1070: 0);
1.1 misho 1071: }
1072:
1073: /* Set aspath attribute flag. */
1074: if (as4_path)
1075: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1076:
1077: return BGP_ATTR_PARSE_PROCEED;
1078: }
1079:
1080: /* Nexthop attribute. */
1081: static bgp_attr_parse_ret_t
1.1.1.2 misho 1082: bgp_attr_nexthop (struct bgp_attr_parser_args *args)
1.1 misho 1083: {
1.1.1.2 misho 1084: struct peer *const peer = args->peer;
1085: struct attr *const attr = args->attr;
1086: const bgp_size_t length = args->length;
1087:
1088: in_addr_t nexthop_h, nexthop_n;
1.1 misho 1089:
1090: /* Check nexthop attribute length. */
1091: if (length != 4)
1092: {
1093: zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1094: length);
1095:
1.1.1.2 misho 1096: return bgp_attr_malformed (args,
1.1 misho 1097: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 1098: args->total);
1.1 misho 1099: }
1100:
1.1.1.2 misho 1101: /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1102: attribute must result in a NOTIFICATION message (this is implemented below).
1103: At the same time, semantically incorrect NEXT_HOP is more likely to be just
1104: logged locally (this is implemented somewhere else). The UPDATE message
1105: gets ignored in any of these cases. */
1106: nexthop_n = stream_get_ipv4 (peer->ibuf);
1107: nexthop_h = ntohl (nexthop_n);
1108: if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1109: {
1110: char buf[INET_ADDRSTRLEN];
1111: inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1112: zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1113: return bgp_attr_malformed (args,
1114: BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1115: args->total);
1116: }
1117:
1118: attr->nexthop.s_addr = nexthop_n;
1.1 misho 1119: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1120:
1121: return BGP_ATTR_PARSE_PROCEED;
1122: }
1123:
1124: /* MED atrribute. */
1125: static bgp_attr_parse_ret_t
1.1.1.2 misho 1126: bgp_attr_med (struct bgp_attr_parser_args *args)
1.1 misho 1127: {
1.1.1.2 misho 1128: struct peer *const peer = args->peer;
1129: struct attr *const attr = args->attr;
1130: const bgp_size_t length = args->length;
1131:
1.1 misho 1132: /* Length check. */
1133: if (length != 4)
1134: {
1135: zlog (peer->log, LOG_ERR,
1136: "MED attribute length isn't four [%d]", length);
1137:
1.1.1.2 misho 1138: return bgp_attr_malformed (args,
1.1 misho 1139: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 1140: args->total);
1.1 misho 1141: }
1142:
1143: attr->med = stream_getl (peer->ibuf);
1144:
1145: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1146:
1147: return BGP_ATTR_PARSE_PROCEED;
1148: }
1149:
1150: /* Local preference attribute. */
1151: static bgp_attr_parse_ret_t
1.1.1.2 misho 1152: bgp_attr_local_pref (struct bgp_attr_parser_args *args)
1.1 misho 1153: {
1.1.1.2 misho 1154: struct peer *const peer = args->peer;
1155: struct attr *const attr = args->attr;
1156: const bgp_size_t length = args->length;
1157:
1158: /* Length check. */
1159: if (length != 4)
1160: {
1161: zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1162: length);
1163: return bgp_attr_malformed (args,
1164: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1165: args->total);
1166: }
1.1 misho 1167:
1168: /* If it is contained in an UPDATE message that is received from an
1169: external peer, then this attribute MUST be ignored by the
1170: receiving speaker. */
1.1.1.3 ! misho 1171: if (peer->sort == BGP_PEER_EBGP)
1.1 misho 1172: {
1173: stream_forward_getp (peer->ibuf, length);
1174: return BGP_ATTR_PARSE_PROCEED;
1175: }
1176:
1.1.1.2 misho 1177: attr->local_pref = stream_getl (peer->ibuf);
1.1 misho 1178:
1179: /* Set atomic aggregate flag. */
1180: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1181:
1182: return BGP_ATTR_PARSE_PROCEED;
1183: }
1184:
1185: /* Atomic aggregate. */
1186: static int
1.1.1.2 misho 1187: bgp_attr_atomic (struct bgp_attr_parser_args *args)
1.1 misho 1188: {
1.1.1.2 misho 1189: struct peer *const peer = args->peer;
1190: struct attr *const attr = args->attr;
1191: const bgp_size_t length = args->length;
1192:
1.1 misho 1193: /* Length check. */
1194: if (length != 0)
1195: {
1.1.1.2 misho 1196: zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1197: length);
1198: return bgp_attr_malformed (args,
1.1 misho 1199: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 1200: args->total);
1.1 misho 1201: }
1202:
1203: /* Set atomic aggregate flag. */
1204: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1205:
1206: return BGP_ATTR_PARSE_PROCEED;
1207: }
1208:
1209: /* Aggregator attribute */
1210: static int
1.1.1.2 misho 1211: bgp_attr_aggregator (struct bgp_attr_parser_args *args)
1.1 misho 1212: {
1.1.1.2 misho 1213: struct peer *const peer = args->peer;
1214: struct attr *const attr = args->attr;
1215: const bgp_size_t length = args->length;
1216:
1.1 misho 1217: int wantedlen = 6;
1218: struct attr_extra *attre = bgp_attr_extra_get (attr);
1219:
1220: /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1221: if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
1222: wantedlen = 8;
1223:
1224: if (length != wantedlen)
1225: {
1.1.1.2 misho 1226: zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1227: wantedlen, length);
1228: return bgp_attr_malformed (args,
1.1 misho 1229: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 1230: args->total);
1.1 misho 1231: }
1232:
1233: if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1234: attre->aggregator_as = stream_getl (peer->ibuf);
1235: else
1236: attre->aggregator_as = stream_getw (peer->ibuf);
1237: attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
1238:
1239: /* Set atomic aggregate flag. */
1240: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1241:
1242: return BGP_ATTR_PARSE_PROCEED;
1243: }
1244:
1245: /* New Aggregator attribute */
1246: static bgp_attr_parse_ret_t
1.1.1.2 misho 1247: bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1248: as_t *as4_aggregator_as,
1249: struct in_addr *as4_aggregator_addr)
1250: {
1251: struct peer *const peer = args->peer;
1252: struct attr *const attr = args->attr;
1253: const bgp_size_t length = args->length;
1254:
1.1 misho 1255: if (length != 8)
1256: {
1.1.1.2 misho 1257: zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1258: length);
1259: return bgp_attr_malformed (args,
1.1 misho 1260: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 1261: 0);
1.1 misho 1262: }
1.1.1.2 misho 1263:
1.1 misho 1264: *as4_aggregator_as = stream_getl (peer->ibuf);
1265: as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1266:
1267: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1268:
1269: return BGP_ATTR_PARSE_PROCEED;
1270: }
1271:
1272: /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1273: */
1274: static bgp_attr_parse_ret_t
1.1.1.2 misho 1275: bgp_attr_munge_as4_attrs (struct peer *const peer,
1276: struct attr *const attr,
1.1 misho 1277: struct aspath *as4_path, as_t as4_aggregator,
1278: struct in_addr *as4_aggregator_addr)
1279: {
1280: int ignore_as4_path = 0;
1281: struct aspath *newpath;
1282: struct attr_extra *attre = attr->extra;
1283:
1284: if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
1285: {
1286: /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1287: * if given.
1288: * It is worth a warning though, because the peer really
1289: * should not send them
1290: */
1291: if (BGP_DEBUG(as4, AS4))
1292: {
1293: if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1294: zlog_debug ("[AS4] %s %s AS4_PATH",
1295: peer->host, "AS4 capable peer, yet it sent");
1296:
1297: if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1298: zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1299: peer->host, "AS4 capable peer, yet it sent");
1300: }
1301:
1302: return BGP_ATTR_PARSE_PROCEED;
1303: }
1304:
1305: /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1306: * because that may override AS4_PATH
1307: */
1308: if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1309: {
1310: if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1311: {
1312: assert (attre);
1313:
1314: /* received both.
1315: * if the as_number in aggregator is not AS_TRANS,
1316: * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1317: * and the Aggregator shall be taken as
1318: * info on the aggregating node, and the AS_PATH
1319: * shall be taken as the AS_PATH
1320: * otherwise
1321: * the Aggregator shall be ignored and the
1322: * AS4_AGGREGATOR shall be taken as the
1323: * Aggregating node and the AS_PATH is to be
1324: * constructed "as in all other cases"
1325: */
1326: if (attre->aggregator_as != BGP_AS_TRANS)
1327: {
1328: /* ignore */
1329: if ( BGP_DEBUG(as4, AS4))
1330: zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1331: " send AGGREGATOR != AS_TRANS and"
1332: " AS4_AGGREGATOR, so ignore"
1333: " AS4_AGGREGATOR and AS4_PATH", peer->host);
1334: ignore_as4_path = 1;
1335: }
1336: else
1337: {
1338: /* "New_aggregator shall be taken as aggregator" */
1339: attre->aggregator_as = as4_aggregator;
1340: attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1341: }
1342: }
1343: else
1344: {
1345: /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1346: * That is bogus - but reading the conditions
1347: * we have to handle AS4_AGGREGATOR as if it were
1348: * AGGREGATOR in that case
1349: */
1350: if ( BGP_DEBUG(as4, AS4))
1351: zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1352: " AS4_AGGREGATOR but no AGGREGATOR, will take"
1353: " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
1354: (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
1355: /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1356: attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1357: }
1358: }
1359:
1360: /* need to reconcile NEW_AS_PATH and AS_PATH */
1361: if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
1362: {
1.1.1.3 ! misho 1363: if (!attr->aspath)
! 1364: return BGP_ATTR_PARSE_PROCEED;
! 1365:
1.1 misho 1366: newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1367: aspath_unintern (&attr->aspath);
1368: attr->aspath = aspath_intern (newpath);
1369: }
1370: return BGP_ATTR_PARSE_PROCEED;
1371: }
1372:
1373: /* Community attribute. */
1374: static bgp_attr_parse_ret_t
1.1.1.2 misho 1375: bgp_attr_community (struct bgp_attr_parser_args *args)
1.1 misho 1376: {
1.1.1.2 misho 1377: struct peer *const peer = args->peer;
1378: struct attr *const attr = args->attr;
1379: const bgp_size_t length = args->length;
1.1 misho 1380:
1381: if (length == 0)
1382: {
1383: attr->community = NULL;
1384: return BGP_ATTR_PARSE_PROCEED;
1385: }
1386:
1387: attr->community =
1388: community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1389:
1390: /* XXX: fix community_parse to use stream API and remove this */
1391: stream_forward_getp (peer->ibuf, length);
1392:
1393: if (!attr->community)
1.1.1.2 misho 1394: return bgp_attr_malformed (args,
1.1 misho 1395: BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1.1.1.2 misho 1396: args->total);
1.1 misho 1397:
1398: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1399:
1400: return BGP_ATTR_PARSE_PROCEED;
1401: }
1402:
1403: /* Originator ID attribute. */
1404: static bgp_attr_parse_ret_t
1.1.1.2 misho 1405: bgp_attr_originator_id (struct bgp_attr_parser_args *args)
1.1 misho 1406: {
1.1.1.2 misho 1407: struct peer *const peer = args->peer;
1408: struct attr *const attr = args->attr;
1409: const bgp_size_t length = args->length;
1410:
1411: /* Length check. */
1.1 misho 1412: if (length != 4)
1413: {
1414: zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1415:
1.1.1.2 misho 1416: return bgp_attr_malformed (args,
1.1 misho 1417: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1.1.1.2 misho 1418: args->total);
1.1 misho 1419: }
1420:
1421: (bgp_attr_extra_get (attr))->originator_id.s_addr
1422: = stream_get_ipv4 (peer->ibuf);
1423:
1424: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1425:
1426: return BGP_ATTR_PARSE_PROCEED;
1427: }
1428:
1429: /* Cluster list attribute. */
1430: static bgp_attr_parse_ret_t
1.1.1.2 misho 1431: bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
1.1 misho 1432: {
1.1.1.2 misho 1433: struct peer *const peer = args->peer;
1434: struct attr *const attr = args->attr;
1435: const bgp_size_t length = args->length;
1436:
1.1 misho 1437: /* Check length. */
1438: if (length % 4)
1439: {
1440: zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1441:
1.1.1.2 misho 1442: return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1443: args->total);
1.1 misho 1444: }
1445:
1446: (bgp_attr_extra_get (attr))->cluster
1447: = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
1448:
1449: /* XXX: Fix cluster_parse to use stream API and then remove this */
1450: stream_forward_getp (peer->ibuf, length);
1451:
1452: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1453:
1454: return BGP_ATTR_PARSE_PROCEED;
1455: }
1456:
1457: /* Multiprotocol reachability information parse. */
1458: int
1.1.1.2 misho 1459: bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1460: struct bgp_nlri *mp_update)
1.1 misho 1461: {
1462: afi_t afi;
1463: safi_t safi;
1464: bgp_size_t nlri_len;
1465: size_t start;
1466: int ret;
1467: struct stream *s;
1.1.1.2 misho 1468: struct peer *const peer = args->peer;
1469: struct attr *const attr = args->attr;
1470: const bgp_size_t length = args->length;
1.1 misho 1471: struct attr_extra *attre = bgp_attr_extra_get(attr);
1472:
1473: /* Set end of packet. */
1474: s = BGP_INPUT(peer);
1475: start = stream_get_getp(s);
1476:
1477: /* safe to read statically sized header? */
1478: #define BGP_MP_REACH_MIN_SIZE 5
1479: #define LEN_LEFT (length - (stream_get_getp(s) - start))
1480: if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1481: {
1482: zlog_info ("%s: %s sent invalid length, %lu",
1483: __func__, peer->host, (unsigned long)length);
1484: return BGP_ATTR_PARSE_ERROR;
1485: }
1486:
1487: /* Load AFI, SAFI. */
1488: afi = stream_getw (s);
1489: safi = stream_getc (s);
1490:
1491: /* Get nexthop length. */
1492: attre->mp_nexthop_len = stream_getc (s);
1493:
1494: if (LEN_LEFT < attre->mp_nexthop_len)
1495: {
1496: zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1497: __func__, peer->host, attre->mp_nexthop_len);
1498: return BGP_ATTR_PARSE_ERROR;
1499: }
1500:
1501: /* Nexthop length check. */
1502: switch (attre->mp_nexthop_len)
1503: {
1504: case 4:
1505: stream_get (&attre->mp_nexthop_global_in, s, 4);
1506: /* Probably needed for RFC 2283 */
1507: if (attr->nexthop.s_addr == 0)
1508: memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
1509: break;
1510: case 12:
1.1.1.2 misho 1511: stream_getl (s); /* RD high */
1512: stream_getl (s); /* RD low */
1513: stream_get (&attre->mp_nexthop_global_in, s, 4);
1.1 misho 1514: break;
1515: #ifdef HAVE_IPV6
1516: case 16:
1517: stream_get (&attre->mp_nexthop_global, s, 16);
1518: break;
1519: case 32:
1520: stream_get (&attre->mp_nexthop_global, s, 16);
1521: stream_get (&attre->mp_nexthop_local, s, 16);
1522: if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
1523: {
1524: char buf1[INET6_ADDRSTRLEN];
1525: char buf2[INET6_ADDRSTRLEN];
1526:
1527: if (BGP_DEBUG (update, UPDATE_IN))
1528: zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
1529: inet_ntop (AF_INET6, &attre->mp_nexthop_global,
1530: buf1, INET6_ADDRSTRLEN),
1531: inet_ntop (AF_INET6, &attre->mp_nexthop_local,
1532: buf2, INET6_ADDRSTRLEN));
1533:
1534: attre->mp_nexthop_len = 16;
1535: }
1536: break;
1537: #endif /* HAVE_IPV6 */
1538: default:
1539: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1540: __func__, peer->host, attre->mp_nexthop_len);
1541: return BGP_ATTR_PARSE_ERROR;
1542: }
1543:
1544: if (!LEN_LEFT)
1545: {
1546: zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1547: __func__, peer->host);
1548: return BGP_ATTR_PARSE_ERROR;
1549: }
1550:
1551: {
1552: u_char val;
1553: if ((val = stream_getc (s)))
1554: zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1555: peer->host, val);
1556: }
1557:
1558: /* must have nrli_len, what is left of the attribute */
1559: nlri_len = LEN_LEFT;
1560: if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1561: {
1562: zlog_info ("%s: (%s) Failed to read NLRI",
1563: __func__, peer->host);
1564: return BGP_ATTR_PARSE_ERROR;
1565: }
1566:
1.1.1.2 misho 1567: if (safi != SAFI_MPLS_LABELED_VPN)
1.1 misho 1568: {
1569: ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1570: if (ret < 0)
1571: {
1572: zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1573: __func__, peer->host);
1574: return BGP_ATTR_PARSE_ERROR;
1575: }
1576: }
1577:
1578: mp_update->afi = afi;
1579: mp_update->safi = safi;
1580: mp_update->nlri = stream_pnt (s);
1581: mp_update->length = nlri_len;
1582:
1583: stream_forward_getp (s, nlri_len);
1584:
1585: return BGP_ATTR_PARSE_PROCEED;
1586: #undef LEN_LEFT
1587: }
1588:
1589: /* Multiprotocol unreachable parse */
1590: int
1.1.1.2 misho 1591: bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
1.1 misho 1592: struct bgp_nlri *mp_withdraw)
1593: {
1594: struct stream *s;
1595: afi_t afi;
1596: safi_t safi;
1597: u_int16_t withdraw_len;
1598: int ret;
1.1.1.2 misho 1599: struct peer *const peer = args->peer;
1600: const bgp_size_t length = args->length;
1.1 misho 1601:
1602: s = peer->ibuf;
1603:
1604: #define BGP_MP_UNREACH_MIN_SIZE 3
1605: if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1606: return BGP_ATTR_PARSE_ERROR;
1607:
1608: afi = stream_getw (s);
1609: safi = stream_getc (s);
1610:
1611: withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
1612:
1.1.1.2 misho 1613: if (safi != SAFI_MPLS_LABELED_VPN)
1.1 misho 1614: {
1615: ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1616: if (ret < 0)
1617: return BGP_ATTR_PARSE_ERROR;
1618: }
1619:
1620: mp_withdraw->afi = afi;
1621: mp_withdraw->safi = safi;
1622: mp_withdraw->nlri = stream_pnt (s);
1623: mp_withdraw->length = withdraw_len;
1624:
1625: stream_forward_getp (s, withdraw_len);
1626:
1627: return BGP_ATTR_PARSE_PROCEED;
1628: }
1629:
1630: /* Extended Community attribute. */
1631: static bgp_attr_parse_ret_t
1.1.1.2 misho 1632: bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
1.1 misho 1633: {
1.1.1.2 misho 1634: struct peer *const peer = args->peer;
1635: struct attr *const attr = args->attr;
1636: const bgp_size_t length = args->length;
1.1 misho 1637:
1638: if (length == 0)
1639: {
1640: if (attr->extra)
1641: attr->extra->ecommunity = NULL;
1642: /* Empty extcomm doesn't seem to be invalid per se */
1643: return BGP_ATTR_PARSE_PROCEED;
1644: }
1645:
1646: (bgp_attr_extra_get (attr))->ecommunity =
1647: ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1648: /* XXX: fix ecommunity_parse to use stream API */
1649: stream_forward_getp (peer->ibuf, length);
1650:
1651: if (!attr->extra->ecommunity)
1.1.1.2 misho 1652: return bgp_attr_malformed (args,
1653: BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1654: args->total);
1.1 misho 1655:
1656: attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1657:
1658: return BGP_ATTR_PARSE_PROCEED;
1659: }
1660:
1661: /* BGP unknown attribute treatment. */
1662: static bgp_attr_parse_ret_t
1.1.1.2 misho 1663: bgp_attr_unknown (struct bgp_attr_parser_args *args)
1.1 misho 1664: {
1.1.1.3 ! misho 1665: bgp_size_t total = args->total;
1.1 misho 1666: struct transit *transit;
1667: struct attr_extra *attre;
1.1.1.2 misho 1668: struct peer *const peer = args->peer;
1669: struct attr *const attr = args->attr;
1670: u_char *const startp = args->startp;
1671: const u_char type = args->type;
1672: const u_char flag = args->flags;
1673: const bgp_size_t length = args->length;
1674:
1.1 misho 1675:
1676: if (BGP_DEBUG (normal, NORMAL))
1677: zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1678: peer->host, type, length);
1679:
1680: if (BGP_DEBUG (events, EVENTS))
1681: zlog (peer->log, LOG_DEBUG,
1682: "Unknown attribute type %d length %d is received", type, length);
1683:
1684: /* Forward read pointer of input stream. */
1685: stream_forward_getp (peer->ibuf, length);
1686:
1687: /* If any of the mandatory well-known attributes are not recognized,
1688: then the Error Subcode is set to Unrecognized Well-known
1689: Attribute. The Data field contains the unrecognized attribute
1690: (type, length and value). */
1691: if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1692: {
1.1.1.2 misho 1693: return bgp_attr_malformed (args,
1.1 misho 1694: BGP_NOTIFY_UPDATE_UNREC_ATTR,
1.1.1.2 misho 1695: args->total);
1.1 misho 1696: }
1697:
1698: /* Unrecognized non-transitive optional attributes must be quietly
1699: ignored and not passed along to other BGP peers. */
1700: if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1701: return BGP_ATTR_PARSE_PROCEED;
1702:
1703: /* If a path with recognized transitive optional attribute is
1704: accepted and passed along to other BGP peers and the Partial bit
1705: in the Attribute Flags octet is set to 1 by some previous AS, it
1706: is not set back to 0 by the current AS. */
1707: SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1708:
1709: /* Store transitive attribute to the end of attr->transit. */
1710: if (! ((attre = bgp_attr_extra_get(attr))->transit) )
1711: attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1712:
1713: transit = attre->transit;
1714:
1715: if (transit->val)
1716: transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1717: transit->length + total);
1718: else
1719: transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1720:
1721: memcpy (transit->val + transit->length, startp, total);
1722: transit->length += total;
1723:
1724: return BGP_ATTR_PARSE_PROCEED;
1725: }
1726:
1727: /* Read attribute of update packet. This function is called from
1.1.1.3 ! misho 1728: bgp_update_receive() in bgp_packet.c. */
1.1 misho 1729: bgp_attr_parse_ret_t
1730: bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1731: struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1732: {
1733: int ret;
1734: u_char flag = 0;
1735: u_char type = 0;
1736: bgp_size_t length;
1737: u_char *startp, *endp;
1738: u_char *attr_endp;
1739: u_char seen[BGP_ATTR_BITMAP_SIZE];
1740: /* we need the as4_path only until we have synthesized the as_path with it */
1741: /* same goes for as4_aggregator */
1742: struct aspath *as4_path = NULL;
1743: as_t as4_aggregator = 0;
1744: struct in_addr as4_aggregator_addr = { 0 };
1745:
1746: /* Initialize bitmap. */
1747: memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1748:
1749: /* End pointer of BGP attribute. */
1750: endp = BGP_INPUT_PNT (peer) + size;
1751:
1752: /* Get attributes to the end of attribute length. */
1753: while (BGP_INPUT_PNT (peer) < endp)
1754: {
1755: /* Check remaining length check.*/
1756: if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1757: {
1758: /* XXX warning: long int format, int arg (arg 5) */
1759: zlog (peer->log, LOG_WARNING,
1760: "%s: error BGP attribute length %lu is smaller than min len",
1761: peer->host,
1762: (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1763:
1764: bgp_notify_send (peer,
1765: BGP_NOTIFY_UPDATE_ERR,
1766: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1767: return BGP_ATTR_PARSE_ERROR;
1768: }
1769:
1770: /* Fetch attribute flag and type. */
1771: startp = BGP_INPUT_PNT (peer);
1.1.1.2 misho 1772: /* "The lower-order four bits of the Attribute Flags octet are
1773: unused. They MUST be zero when sent and MUST be ignored when
1774: received." */
1775: flag = 0xF0 & stream_getc (BGP_INPUT (peer));
1.1 misho 1776: type = stream_getc (BGP_INPUT (peer));
1777:
1778: /* Check whether Extended-Length applies and is in bounds */
1779: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1780: && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1781: {
1782: zlog (peer->log, LOG_WARNING,
1783: "%s: Extended length set, but just %lu bytes of attr header",
1784: peer->host,
1785: (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1786:
1787: bgp_notify_send (peer,
1788: BGP_NOTIFY_UPDATE_ERR,
1789: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1790: return BGP_ATTR_PARSE_ERROR;
1791: }
1.1.1.2 misho 1792:
1.1 misho 1793: /* Check extended attribue length bit. */
1794: if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1795: length = stream_getw (BGP_INPUT (peer));
1796: else
1797: length = stream_getc (BGP_INPUT (peer));
1798:
1799: /* If any attribute appears more than once in the UPDATE
1800: message, then the Error Subcode is set to Malformed Attribute
1801: List. */
1802:
1803: if (CHECK_BITMAP (seen, type))
1804: {
1805: zlog (peer->log, LOG_WARNING,
1806: "%s: error BGP attribute type %d appears twice in a message",
1807: peer->host, type);
1808:
1809: bgp_notify_send (peer,
1810: BGP_NOTIFY_UPDATE_ERR,
1811: BGP_NOTIFY_UPDATE_MAL_ATTR);
1812: return BGP_ATTR_PARSE_ERROR;
1813: }
1814:
1815: /* Set type to bitmap to check duplicate attribute. `type' is
1816: unsigned char so it never overflow bitmap range. */
1817:
1818: SET_BITMAP (seen, type);
1819:
1820: /* Overflow check. */
1821: attr_endp = BGP_INPUT_PNT (peer) + length;
1822:
1823: if (attr_endp > endp)
1824: {
1825: zlog (peer->log, LOG_WARNING,
1826: "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
1827: bgp_notify_send (peer,
1828: BGP_NOTIFY_UPDATE_ERR,
1829: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1830: return BGP_ATTR_PARSE_ERROR;
1831: }
1.1.1.2 misho 1832:
1833: struct bgp_attr_parser_args attr_args = {
1834: .peer = peer,
1835: .length = length,
1836: .attr = attr,
1837: .type = type,
1838: .flags = flag,
1839: .startp = startp,
1840: .total = attr_endp - startp,
1841: };
1842:
1843:
1844: /* If any recognized attribute has Attribute Flags that conflict
1845: with the Attribute Type Code, then the Error Subcode is set to
1846: Attribute Flags Error. The Data field contains the erroneous
1847: attribute (type, length and value). */
1848: if (bgp_attr_flag_invalid (&attr_args))
1849: {
1850: bgp_attr_parse_ret_t ret;
1851: ret = bgp_attr_malformed (&attr_args,
1852: BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1853: attr_args.total);
1854: if (ret == BGP_ATTR_PARSE_PROCEED)
1855: continue;
1856: return ret;
1857: }
1.1 misho 1858:
1859: /* OK check attribute and store it's value. */
1860: switch (type)
1861: {
1862: case BGP_ATTR_ORIGIN:
1.1.1.2 misho 1863: ret = bgp_attr_origin (&attr_args);
1.1 misho 1864: break;
1865: case BGP_ATTR_AS_PATH:
1.1.1.2 misho 1866: ret = bgp_attr_aspath (&attr_args);
1.1 misho 1867: break;
1868: case BGP_ATTR_AS4_PATH:
1.1.1.2 misho 1869: ret = bgp_attr_as4_path (&attr_args, &as4_path);
1.1 misho 1870: break;
1871: case BGP_ATTR_NEXT_HOP:
1.1.1.2 misho 1872: ret = bgp_attr_nexthop (&attr_args);
1.1 misho 1873: break;
1874: case BGP_ATTR_MULTI_EXIT_DISC:
1.1.1.2 misho 1875: ret = bgp_attr_med (&attr_args);
1.1 misho 1876: break;
1877: case BGP_ATTR_LOCAL_PREF:
1.1.1.2 misho 1878: ret = bgp_attr_local_pref (&attr_args);
1.1 misho 1879: break;
1880: case BGP_ATTR_ATOMIC_AGGREGATE:
1.1.1.2 misho 1881: ret = bgp_attr_atomic (&attr_args);
1.1 misho 1882: break;
1883: case BGP_ATTR_AGGREGATOR:
1.1.1.2 misho 1884: ret = bgp_attr_aggregator (&attr_args);
1.1 misho 1885: break;
1886: case BGP_ATTR_AS4_AGGREGATOR:
1.1.1.2 misho 1887: ret = bgp_attr_as4_aggregator (&attr_args,
1888: &as4_aggregator,
1.1 misho 1889: &as4_aggregator_addr);
1890: break;
1891: case BGP_ATTR_COMMUNITIES:
1.1.1.2 misho 1892: ret = bgp_attr_community (&attr_args);
1.1 misho 1893: break;
1894: case BGP_ATTR_ORIGINATOR_ID:
1.1.1.2 misho 1895: ret = bgp_attr_originator_id (&attr_args);
1.1 misho 1896: break;
1897: case BGP_ATTR_CLUSTER_LIST:
1.1.1.2 misho 1898: ret = bgp_attr_cluster_list (&attr_args);
1.1 misho 1899: break;
1900: case BGP_ATTR_MP_REACH_NLRI:
1.1.1.2 misho 1901: ret = bgp_mp_reach_parse (&attr_args, mp_update);
1.1 misho 1902: break;
1903: case BGP_ATTR_MP_UNREACH_NLRI:
1.1.1.2 misho 1904: ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
1.1 misho 1905: break;
1906: case BGP_ATTR_EXT_COMMUNITIES:
1.1.1.2 misho 1907: ret = bgp_attr_ext_communities (&attr_args);
1.1 misho 1908: break;
1909: default:
1.1.1.2 misho 1910: ret = bgp_attr_unknown (&attr_args);
1.1 misho 1911: break;
1912: }
1913:
1914: /* If hard error occured immediately return to the caller. */
1915: if (ret == BGP_ATTR_PARSE_ERROR)
1916: {
1917: zlog (peer->log, LOG_WARNING,
1918: "%s: Attribute %s, parse error",
1919: peer->host,
1920: LOOKUP (attr_str, type));
1921: bgp_notify_send (peer,
1922: BGP_NOTIFY_UPDATE_ERR,
1923: BGP_NOTIFY_UPDATE_MAL_ATTR);
1924: if (as4_path)
1925: aspath_unintern (&as4_path);
1926: return ret;
1927: }
1928: if (ret == BGP_ATTR_PARSE_WITHDRAW)
1929: {
1930:
1931: zlog (peer->log, LOG_WARNING,
1932: "%s: Attribute %s, parse error - treating as withdrawal",
1933: peer->host,
1934: LOOKUP (attr_str, type));
1935: if (as4_path)
1936: aspath_unintern (&as4_path);
1937: return ret;
1938: }
1939:
1940: /* Check the fetched length. */
1941: if (BGP_INPUT_PNT (peer) != attr_endp)
1942: {
1943: zlog (peer->log, LOG_WARNING,
1944: "%s: BGP attribute %s, fetch error",
1945: peer->host, LOOKUP (attr_str, type));
1946: bgp_notify_send (peer,
1947: BGP_NOTIFY_UPDATE_ERR,
1948: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1949: if (as4_path)
1950: aspath_unintern (&as4_path);
1951: return BGP_ATTR_PARSE_ERROR;
1952: }
1953: }
1954:
1955: /* Check final read pointer is same as end pointer. */
1956: if (BGP_INPUT_PNT (peer) != endp)
1957: {
1958: zlog (peer->log, LOG_WARNING,
1959: "%s: BGP attribute %s, length mismatch",
1960: peer->host, LOOKUP (attr_str, type));
1961: bgp_notify_send (peer,
1962: BGP_NOTIFY_UPDATE_ERR,
1963: BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1964: if (as4_path)
1965: aspath_unintern (&as4_path);
1966: return BGP_ATTR_PARSE_ERROR;
1967: }
1968:
1969: /*
1970: * At this place we can see whether we got AS4_PATH and/or
1971: * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1972: * We can not do this before we've read all attributes because
1973: * the as4 handling does not say whether AS4_PATH has to be sent
1974: * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1975: * in relationship to AGGREGATOR.
1976: * So, to be defensive, we are not relying on any order and read
1977: * all attributes first, including these 32bit ones, and now,
1978: * afterwards, we look what and if something is to be done for as4.
1979: */
1.1.1.2 misho 1980: if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1.1 misho 1981: as4_aggregator, &as4_aggregator_addr))
1982: {
1983: if (as4_path)
1984: aspath_unintern (&as4_path);
1985: return BGP_ATTR_PARSE_ERROR;
1986: }
1987:
1988: /* At this stage, we have done all fiddling with as4, and the
1989: * resulting info is in attr->aggregator resp. attr->aspath
1990: * so we can chuck as4_aggregator and as4_path alltogether in
1991: * order to save memory
1992: */
1993: if (as4_path)
1994: {
1995: aspath_unintern (&as4_path); /* unintern - it is in the hash */
1996: /* The flag that we got this is still there, but that does not
1997: * do any trouble
1998: */
1999: }
2000: /*
2001: * The "rest" of the code does nothing with as4_aggregator.
2002: * there is no memory attached specifically which is not part
2003: * of the attr.
2004: * so ignoring just means do nothing.
2005: */
2006: /*
2007: * Finally do the checks on the aspath we did not do yet
2008: * because we waited for a potentially synthesized aspath.
2009: */
2010: if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
2011: {
1.1.1.2 misho 2012: ret = bgp_attr_aspath_check (peer, attr);
1.1 misho 2013: if (ret != BGP_ATTR_PARSE_PROCEED)
2014: return ret;
2015: }
2016:
2017: /* Finally intern unknown attribute. */
2018: if (attr->extra && attr->extra->transit)
2019: attr->extra->transit = transit_intern (attr->extra->transit);
2020:
2021: return BGP_ATTR_PARSE_PROCEED;
2022: }
2023:
2024: /* Well-known attribute check. */
2025: int
2026: bgp_attr_check (struct peer *peer, struct attr *attr)
2027: {
2028: u_char type = 0;
2029:
2030: if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2031: type = BGP_ATTR_ORIGIN;
2032:
2033: if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2034: type = BGP_ATTR_AS_PATH;
2035:
2036: if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2037: type = BGP_ATTR_NEXT_HOP;
2038:
1.1.1.3 ! misho 2039: if (peer->sort == BGP_PEER_IBGP
1.1 misho 2040: && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2041: type = BGP_ATTR_LOCAL_PREF;
2042:
2043: if (type)
2044: {
2045: zlog (peer->log, LOG_WARNING,
2046: "%s Missing well-known attribute %d.",
2047: peer->host, type);
2048: bgp_notify_send_with_data (peer,
2049: BGP_NOTIFY_UPDATE_ERR,
2050: BGP_NOTIFY_UPDATE_MISS_ATTR,
2051: &type, 1);
2052: return BGP_ATTR_PARSE_ERROR;
2053: }
2054: return BGP_ATTR_PARSE_PROCEED;
2055: }
2056:
2057: int stream_put_prefix (struct stream *, struct prefix *);
2058:
2059: /* Make attribute packet. */
2060: bgp_size_t
2061: bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2062: struct stream *s, struct attr *attr, struct prefix *p,
2063: afi_t afi, safi_t safi, struct peer *from,
2064: struct prefix_rd *prd, u_char *tag)
2065: {
2066: size_t cp;
2067: size_t aspath_sizep;
2068: struct aspath *aspath;
2069: int send_as4_path = 0;
2070: int send_as4_aggregator = 0;
2071: int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
2072:
2073: if (! bgp)
2074: bgp = bgp_get_default ();
2075:
2076: /* Remember current pointer. */
2077: cp = stream_get_endp (s);
2078:
2079: /* Origin attribute. */
2080: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2081: stream_putc (s, BGP_ATTR_ORIGIN);
2082: stream_putc (s, 1);
2083: stream_putc (s, attr->origin);
2084:
2085: /* AS path attribute. */
2086:
2087: /* If remote-peer is EBGP */
1.1.1.3 ! misho 2088: if (peer->sort == BGP_PEER_EBGP
1.1 misho 2089: && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
2090: || attr->aspath->segments == NULL)
2091: && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
2092: {
2093: aspath = aspath_dup (attr->aspath);
2094:
2095: if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2096: {
2097: /* Strip the confed info, and then stuff our path CONFED_ID
2098: on the front */
2099: aspath = aspath_delete_confed_seq (aspath);
2100: aspath = aspath_add_seq (aspath, bgp->confed_id);
2101: }
2102: else
2103: {
1.1.1.3 ! misho 2104: if (peer->change_local_as) {
! 2105: /* If replace-as is specified, we only use the change_local_as when
! 2106: advertising routes. */
! 2107: if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
! 2108: aspath = aspath_add_seq (aspath, peer->local_as);
! 2109: }
1.1 misho 2110: aspath = aspath_add_seq (aspath, peer->change_local_as);
1.1.1.3 ! misho 2111: } else {
! 2112: aspath = aspath_add_seq (aspath, peer->local_as);
! 2113: }
1.1 misho 2114: }
2115: }
1.1.1.3 ! misho 2116: else if (peer->sort == BGP_PEER_CONFED)
1.1 misho 2117: {
2118: /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2119: aspath = aspath_dup (attr->aspath);
2120: aspath = aspath_add_confed_seq (aspath, peer->local_as);
2121: }
2122: else
2123: aspath = attr->aspath;
2124:
2125: /* If peer is not AS4 capable, then:
2126: * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2127: * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2128: * types are in it (i.e. exclude them if they are there)
2129: * AND do this only if there is at least one asnum > 65535 in the path!
2130: * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2131: * all ASnums > 65535 to BGP_AS_TRANS
2132: */
2133:
2134: stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2135: stream_putc (s, BGP_ATTR_AS_PATH);
2136: aspath_sizep = stream_get_endp (s);
2137: stream_putw (s, 0);
2138: stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2139:
2140: /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2141: * in the path
2142: */
2143: if (!use32bit && aspath_has_as4 (aspath))
2144: send_as4_path = 1; /* we'll do this later, at the correct place */
2145:
2146: /* Nexthop attribute. */
2147: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2148: {
2149: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2150: stream_putc (s, BGP_ATTR_NEXT_HOP);
2151: stream_putc (s, 4);
2152: if (safi == SAFI_MPLS_VPN)
2153: {
2154: if (attr->nexthop.s_addr == 0)
2155: stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2156: else
2157: stream_put_ipv4 (s, attr->nexthop.s_addr);
2158: }
2159: else
2160: stream_put_ipv4 (s, attr->nexthop.s_addr);
2161: }
2162:
2163: /* MED attribute. */
2164: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2165: {
2166: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2167: stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2168: stream_putc (s, 4);
2169: stream_putl (s, attr->med);
2170: }
2171:
2172: /* Local preference. */
1.1.1.3 ! misho 2173: if (peer->sort == BGP_PEER_IBGP ||
! 2174: peer->sort == BGP_PEER_CONFED)
1.1 misho 2175: {
2176: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2177: stream_putc (s, BGP_ATTR_LOCAL_PREF);
2178: stream_putc (s, 4);
2179: stream_putl (s, attr->local_pref);
2180: }
2181:
2182: /* Atomic aggregate. */
2183: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2184: {
2185: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2186: stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2187: stream_putc (s, 0);
2188: }
2189:
2190: /* Aggregator. */
2191: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2192: {
2193: assert (attr->extra);
2194:
2195: /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
2196: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2197: stream_putc (s, BGP_ATTR_AGGREGATOR);
2198:
2199: if (use32bit)
2200: {
2201: /* AS4 capable peer */
2202: stream_putc (s, 8);
2203: stream_putl (s, attr->extra->aggregator_as);
2204: }
2205: else
2206: {
2207: /* 2-byte AS peer */
2208: stream_putc (s, 6);
2209:
2210: /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2211: if ( attr->extra->aggregator_as > 65535 )
2212: {
2213: stream_putw (s, BGP_AS_TRANS);
2214:
2215: /* we have to send AS4_AGGREGATOR, too.
2216: * we'll do that later in order to send attributes in ascending
2217: * order.
2218: */
2219: send_as4_aggregator = 1;
2220: }
2221: else
2222: stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2223: }
2224: stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2225: }
2226:
2227: /* Community attribute. */
2228: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2229: && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2230: {
2231: if (attr->community->size * 4 > 255)
2232: {
2233: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2234: stream_putc (s, BGP_ATTR_COMMUNITIES);
2235: stream_putw (s, attr->community->size * 4);
2236: }
2237: else
2238: {
2239: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2240: stream_putc (s, BGP_ATTR_COMMUNITIES);
2241: stream_putc (s, attr->community->size * 4);
2242: }
2243: stream_put (s, attr->community->val, attr->community->size * 4);
2244: }
2245:
2246: /* Route Reflector. */
1.1.1.3 ! misho 2247: if (peer->sort == BGP_PEER_IBGP
1.1 misho 2248: && from
1.1.1.3 ! misho 2249: && from->sort == BGP_PEER_IBGP)
1.1 misho 2250: {
2251: /* Originator ID. */
2252: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2253: stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2254: stream_putc (s, 4);
2255:
2256: if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
2257: stream_put_in_addr (s, &attr->extra->originator_id);
2258: else
2259: stream_put_in_addr (s, &from->remote_id);
2260:
2261: /* Cluster list. */
2262: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2263: stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2264:
2265: if (attr->extra && attr->extra->cluster)
2266: {
2267: stream_putc (s, attr->extra->cluster->length + 4);
2268: /* If this peer configuration's parent BGP has cluster_id. */
2269: if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2270: stream_put_in_addr (s, &bgp->cluster_id);
2271: else
2272: stream_put_in_addr (s, &bgp->router_id);
2273: stream_put (s, attr->extra->cluster->list,
2274: attr->extra->cluster->length);
2275: }
2276: else
2277: {
2278: stream_putc (s, 4);
2279: /* If this peer configuration's parent BGP has cluster_id. */
2280: if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2281: stream_put_in_addr (s, &bgp->cluster_id);
2282: else
2283: stream_put_in_addr (s, &bgp->router_id);
2284: }
2285: }
2286:
2287: #ifdef HAVE_IPV6
2288: /* If p is IPv6 address put it into attribute. */
2289: if (p->family == AF_INET6)
2290: {
2291: unsigned long sizep;
2292: struct attr_extra *attre = attr->extra;
2293:
2294: assert (attr->extra);
2295:
2296: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2297: stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2298: sizep = stream_get_endp (s);
2299: stream_putc (s, 0); /* Marker: Attribute length. */
2300: stream_putw (s, AFI_IP6); /* AFI */
2301: stream_putc (s, safi); /* SAFI */
2302:
2303: stream_putc (s, attre->mp_nexthop_len);
2304:
2305: if (attre->mp_nexthop_len == 16)
2306: stream_put (s, &attre->mp_nexthop_global, 16);
2307: else if (attre->mp_nexthop_len == 32)
2308: {
2309: stream_put (s, &attre->mp_nexthop_global, 16);
2310: stream_put (s, &attre->mp_nexthop_local, 16);
2311: }
2312:
2313: /* SNPA */
2314: stream_putc (s, 0);
2315:
2316: /* Prefix write. */
2317: stream_put_prefix (s, p);
2318:
2319: /* Set MP attribute length. */
2320: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2321: }
2322: #endif /* HAVE_IPV6 */
2323:
2324: if (p->family == AF_INET && safi == SAFI_MULTICAST)
2325: {
2326: unsigned long sizep;
2327:
2328: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2329: stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2330: sizep = stream_get_endp (s);
2331: stream_putc (s, 0); /* Marker: Attribute Length. */
2332: stream_putw (s, AFI_IP); /* AFI */
2333: stream_putc (s, SAFI_MULTICAST); /* SAFI */
2334:
2335: stream_putc (s, 4);
2336: stream_put_ipv4 (s, attr->nexthop.s_addr);
2337:
2338: /* SNPA */
2339: stream_putc (s, 0);
2340:
2341: /* Prefix write. */
2342: stream_put_prefix (s, p);
2343:
2344: /* Set MP attribute length. */
2345: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2346: }
2347:
2348: if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2349: {
2350: unsigned long sizep;
2351:
2352: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2353: stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2354: sizep = stream_get_endp (s);
2355: stream_putc (s, 0); /* Length of this attribute. */
2356: stream_putw (s, AFI_IP); /* AFI */
1.1.1.2 misho 2357: stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
1.1 misho 2358:
2359: stream_putc (s, 12);
2360: stream_putl (s, 0);
2361: stream_putl (s, 0);
2362: stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
2363:
2364: /* SNPA */
2365: stream_putc (s, 0);
2366:
2367: /* Tag, RD, Prefix write. */
2368: stream_putc (s, p->prefixlen + 88);
2369: stream_put (s, tag, 3);
2370: stream_put (s, prd->val, 8);
2371: stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2372:
2373: /* Set MP attribute length. */
2374: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2375: }
2376:
2377: /* Extended Communities attribute. */
2378: if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2379: && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2380: {
2381: struct attr_extra *attre = attr->extra;
2382:
2383: assert (attre);
2384:
1.1.1.3 ! misho 2385: if (peer->sort == BGP_PEER_IBGP
! 2386: || peer->sort == BGP_PEER_CONFED)
1.1 misho 2387: {
2388: if (attre->ecommunity->size * 8 > 255)
2389: {
2390: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2391: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2392: stream_putw (s, attre->ecommunity->size * 8);
2393: }
2394: else
2395: {
2396: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2397: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2398: stream_putc (s, attre->ecommunity->size * 8);
2399: }
2400: stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
2401: }
2402: else
2403: {
2404: u_int8_t *pnt;
2405: int tbit;
2406: int ecom_tr_size = 0;
2407: int i;
2408:
2409: for (i = 0; i < attre->ecommunity->size; i++)
2410: {
2411: pnt = attre->ecommunity->val + (i * 8);
2412: tbit = *pnt;
2413:
2414: if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2415: continue;
2416:
2417: ecom_tr_size++;
2418: }
2419:
2420: if (ecom_tr_size)
2421: {
2422: if (ecom_tr_size * 8 > 255)
2423: {
2424: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2425: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2426: stream_putw (s, ecom_tr_size * 8);
2427: }
2428: else
2429: {
2430: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2431: stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2432: stream_putc (s, ecom_tr_size * 8);
2433: }
2434:
2435: for (i = 0; i < attre->ecommunity->size; i++)
2436: {
2437: pnt = attre->ecommunity->val + (i * 8);
2438: tbit = *pnt;
2439:
2440: if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2441: continue;
2442:
2443: stream_put (s, pnt, 8);
2444: }
2445: }
2446: }
2447: }
2448:
2449: if ( send_as4_path )
2450: {
2451: /* If the peer is NOT As4 capable, AND */
2452: /* there are ASnums > 65535 in path THEN
2453: * give out AS4_PATH */
2454:
2455: /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2456: * path segments!
2457: * Hm, I wonder... confederation things *should* only be at
2458: * the beginning of an aspath, right? Then we should use
2459: * aspath_delete_confed_seq for this, because it is already
2460: * there! (JK)
2461: * Folks, talk to me: what is reasonable here!?
2462: */
2463: aspath = aspath_delete_confed_seq (aspath);
2464:
2465: stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2466: stream_putc (s, BGP_ATTR_AS4_PATH);
2467: aspath_sizep = stream_get_endp (s);
2468: stream_putw (s, 0);
2469: stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2470: }
2471:
2472: if (aspath != attr->aspath)
2473: aspath_free (aspath);
2474:
2475: if ( send_as4_aggregator )
2476: {
2477: assert (attr->extra);
2478:
2479: /* send AS4_AGGREGATOR, at this place */
2480: /* this section of code moved here in order to ensure the correct
2481: * *ascending* order of attributes
2482: */
2483: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2484: stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2485: stream_putc (s, 8);
2486: stream_putl (s, attr->extra->aggregator_as);
2487: stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2488: }
2489:
2490: /* Unknown transit attribute. */
2491: if (attr->extra && attr->extra->transit)
2492: stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
2493:
2494: /* Return total size of attribute. */
2495: return stream_get_endp (s) - cp;
2496: }
2497:
2498: bgp_size_t
2499: bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2500: afi_t afi, safi_t safi, struct prefix_rd *prd,
2501: u_char *tag)
2502: {
2503: unsigned long cp;
2504: unsigned long attrlen_pnt;
2505: bgp_size_t size;
2506:
2507: cp = stream_get_endp (s);
2508:
2509: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2510: stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2511:
2512: attrlen_pnt = stream_get_endp (s);
2513: stream_putc (s, 0); /* Length of this attribute. */
2514:
2515: stream_putw (s, family2afi (p->family));
2516:
2517: if (safi == SAFI_MPLS_VPN)
2518: {
2519: /* SAFI */
1.1.1.2 misho 2520: stream_putc (s, SAFI_MPLS_LABELED_VPN);
1.1 misho 2521:
2522: /* prefix. */
2523: stream_putc (s, p->prefixlen + 88);
2524: stream_put (s, tag, 3);
2525: stream_put (s, prd->val, 8);
2526: stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2527: }
2528: else
2529: {
2530: /* SAFI */
2531: stream_putc (s, safi);
2532:
2533: /* prefix */
2534: stream_put_prefix (s, p);
2535: }
2536:
2537: /* Set MP attribute length. */
2538: size = stream_get_endp (s) - attrlen_pnt - 1;
2539: stream_putc_at (s, attrlen_pnt, size);
2540:
2541: return stream_get_endp (s) - cp;
2542: }
2543:
2544: /* Initialization of attribute. */
2545: void
2546: bgp_attr_init (void)
2547: {
2548: aspath_init ();
2549: attrhash_init ();
2550: community_init ();
2551: ecommunity_init ();
2552: cluster_init ();
2553: transit_init ();
2554: }
2555:
2556: void
2557: bgp_attr_finish (void)
2558: {
2559: aspath_finish ();
2560: attrhash_finish ();
2561: community_finish ();
2562: ecommunity_finish ();
2563: cluster_finish ();
2564: transit_finish ();
2565: }
2566:
2567: /* Make attribute packet. */
2568: void
2569: bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2570: struct prefix *prefix)
2571: {
2572: unsigned long cp;
2573: unsigned long len;
2574: size_t aspath_lenp;
2575: struct aspath *aspath;
2576:
2577: /* Remember current pointer. */
2578: cp = stream_get_endp (s);
2579:
2580: /* Place holder of length. */
2581: stream_putw (s, 0);
2582:
2583: /* Origin attribute. */
2584: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2585: stream_putc (s, BGP_ATTR_ORIGIN);
2586: stream_putc (s, 1);
2587: stream_putc (s, attr->origin);
2588:
2589: aspath = attr->aspath;
2590:
2591: stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2592: stream_putc (s, BGP_ATTR_AS_PATH);
2593: aspath_lenp = stream_get_endp (s);
2594: stream_putw (s, 0);
2595:
2596: stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
2597:
2598: /* Nexthop attribute. */
2599: /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2600: if(prefix != NULL
2601: #ifdef HAVE_IPV6
2602: && prefix->family != AF_INET6
2603: #endif /* HAVE_IPV6 */
2604: )
2605: {
2606: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2607: stream_putc (s, BGP_ATTR_NEXT_HOP);
2608: stream_putc (s, 4);
2609: stream_put_ipv4 (s, attr->nexthop.s_addr);
2610: }
2611:
2612: /* MED attribute. */
2613: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2614: {
2615: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2616: stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2617: stream_putc (s, 4);
2618: stream_putl (s, attr->med);
2619: }
2620:
2621: /* Local preference. */
2622: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2623: {
2624: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2625: stream_putc (s, BGP_ATTR_LOCAL_PREF);
2626: stream_putc (s, 4);
2627: stream_putl (s, attr->local_pref);
2628: }
2629:
2630: /* Atomic aggregate. */
2631: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2632: {
2633: stream_putc (s, BGP_ATTR_FLAG_TRANS);
2634: stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2635: stream_putc (s, 0);
2636: }
2637:
2638: /* Aggregator. */
2639: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2640: {
2641: assert (attr->extra);
2642: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2643: stream_putc (s, BGP_ATTR_AGGREGATOR);
2644: stream_putc (s, 8);
2645: stream_putl (s, attr->extra->aggregator_as);
2646: stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2647: }
2648:
2649: /* Community attribute. */
2650: if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2651: {
2652: if (attr->community->size * 4 > 255)
2653: {
2654: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2655: stream_putc (s, BGP_ATTR_COMMUNITIES);
2656: stream_putw (s, attr->community->size * 4);
2657: }
2658: else
2659: {
2660: stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2661: stream_putc (s, BGP_ATTR_COMMUNITIES);
2662: stream_putc (s, attr->community->size * 4);
2663: }
2664: stream_put (s, attr->community->val, attr->community->size * 4);
2665: }
2666:
2667: #ifdef HAVE_IPV6
2668: /* Add a MP_NLRI attribute to dump the IPv6 next hop */
2669: if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2670: (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
2671: {
2672: int sizep;
2673: struct attr_extra *attre = attr->extra;
2674:
2675: stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2676: stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
2677: sizep = stream_get_endp (s);
2678:
2679: /* MP header */
2680: stream_putc (s, 0); /* Marker: Attribute length. */
2681: stream_putw(s, AFI_IP6); /* AFI */
2682: stream_putc(s, SAFI_UNICAST); /* SAFI */
2683:
2684: /* Next hop */
2685: stream_putc(s, attre->mp_nexthop_len);
2686: stream_put(s, &attre->mp_nexthop_global, 16);
2687: if (attre->mp_nexthop_len == 32)
2688: stream_put(s, &attre->mp_nexthop_local, 16);
2689:
2690: /* SNPA */
2691: stream_putc(s, 0);
2692:
2693: /* Prefix */
2694: stream_put_prefix(s, prefix);
2695:
2696: /* Set MP attribute length. */
2697: stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2698: }
2699: #endif /* HAVE_IPV6 */
2700:
2701: /* Return total size of attribute. */
2702: len = stream_get_endp (s) - cp - 2;
2703: stream_putw_at (s, cp, len);
2704: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>