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