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