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