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