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