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