]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_attr.c
zebra, bgpd, ospfd: 'redistribute table' to 'redistribute table <table-id>'
[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};
837d16cc 77static const size_t attr_flag_str_max = array_size(attr_flag_str);
6b0655a2 78
9bddac4b 79static struct hash *cluster_hash;
718e3744 80
94f2b392 81static void *
923de654 82cluster_hash_alloc (void *p)
718e3744 83{
ffd0c037 84 const struct cluster_list *val = (const struct cluster_list *) p;
718e3744 85 struct cluster_list *cluster;
86
87 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
88 cluster->length = val->length;
89
90 if (cluster->length)
91 {
92 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
93 memcpy (cluster->list, val->list, val->length);
94 }
95 else
96 cluster->list = NULL;
97
98 cluster->refcnt = 0;
99
100 return cluster;
101}
102
103/* Cluster list related functions. */
94f2b392 104static struct cluster_list *
5228ad27 105cluster_parse (struct in_addr * pnt, int length)
718e3744 106{
107 struct cluster_list tmp;
108 struct cluster_list *cluster;
109
110 tmp.length = length;
5228ad27 111 tmp.list = pnt;
718e3744 112
113 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
114 cluster->refcnt++;
115 return cluster;
116}
117
118int
119cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
120{
121 int i;
122
123 for (i = 0; i < cluster->length / 4; i++)
124 if (cluster->list[i].s_addr == originator.s_addr)
125 return 1;
126 return 0;
127}
128
94f2b392 129static unsigned int
923de654 130cluster_hash_key_make (void *p)
718e3744 131{
c8e7b895 132 const struct cluster_list *cluster = p;
718e3744 133
c8e7b895 134 return jhash(cluster->list, cluster->length, 0);
718e3744 135}
136
94f2b392 137static int
ffe11cfb 138cluster_hash_cmp (const void *p1, const void *p2)
718e3744 139{
ffe11cfb
SH
140 const struct cluster_list * cluster1 = p1;
141 const struct cluster_list * cluster2 = p2;
923de654 142
ffe11cfb
SH
143 return (cluster1->length == cluster2->length &&
144 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
718e3744 145}
146
94f2b392 147static void
718e3744 148cluster_free (struct cluster_list *cluster)
149{
150 if (cluster->list)
151 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
152 XFREE (MTYPE_CLUSTER, cluster);
153}
154
94f2b392 155static struct cluster_list *
718e3744 156cluster_dup (struct cluster_list *cluster)
157{
158 struct cluster_list *new;
159
393deb9b 160 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
718e3744 161 new->length = cluster->length;
162
163 if (cluster->length)
164 {
165 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
166 memcpy (new->list, cluster->list, cluster->length);
167 }
168 else
169 new->list = NULL;
170
171 return new;
172}
173
94f2b392 174static struct cluster_list *
718e3744 175cluster_intern (struct cluster_list *cluster)
176{
177 struct cluster_list *find;
178
179 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
180 find->refcnt++;
181
182 return find;
183}
184
185void
186cluster_unintern (struct cluster_list *cluster)
187{
718e3744 188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
9206f9ec 193 hash_release (cluster_hash, cluster);
718e3744 194 cluster_free (cluster);
195 }
196}
197
94f2b392 198static void
199cluster_init (void)
718e3744 200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
228da428
CC
203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
6b0655a2 210
718e3744 211/* Unknown transit attribute. */
9bddac4b 212static struct hash *transit_hash;
718e3744 213
94f2b392 214static void
718e3744 215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
73ac8160
DS
222static struct transit *
223transit_dup (struct transit *transit)
224{
225 struct transit *new;
226
227 new = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
228 new->length = transit->length;
229 if (new->length)
230 {
231 new->val = XMALLOC (MTYPE_TRANSIT_VAL, transit->length);
232 memcpy (new->val, transit->val, transit->length);
233 }
234 else
235 new->val = NULL;
236
237 return new;
238}
923de654 239
94f2b392 240static void *
923de654 241transit_hash_alloc (void *p)
718e3744 242{
243 /* Transit structure is already allocated. */
923de654 244 return p;
718e3744 245}
246
94f2b392 247static struct transit *
718e3744 248transit_intern (struct transit *transit)
249{
250 struct transit *find;
251
252 find = hash_get (transit_hash, transit, transit_hash_alloc);
253 if (find != transit)
254 transit_free (transit);
255 find->refcnt++;
256
257 return find;
258}
259
260void
261transit_unintern (struct transit *transit)
262{
718e3744 263 if (transit->refcnt)
264 transit->refcnt--;
265
266 if (transit->refcnt == 0)
267 {
9206f9ec 268 hash_release (transit_hash, transit);
718e3744 269 transit_free (transit);
270 }
271}
272
94f2b392 273static unsigned int
923de654 274transit_hash_key_make (void *p)
718e3744 275{
c8e7b895 276 const struct transit * transit = p;
718e3744 277
c8e7b895 278 return jhash(transit->val, transit->length, 0);
718e3744 279}
280
94f2b392 281static int
ffe11cfb 282transit_hash_cmp (const void *p1, const void *p2)
718e3744 283{
ffe11cfb
SH
284 const struct transit * transit1 = p1;
285 const struct transit * transit2 = p2;
923de654 286
ffe11cfb
SH
287 return (transit1->length == transit2->length &&
288 memcmp (transit1->val, transit2->val, transit1->length) == 0);
718e3744 289}
290
94f2b392 291static void
66e5cd87 292transit_init (void)
718e3744 293{
294 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
295}
228da428
CC
296
297static void
298transit_finish (void)
299{
300 hash_free (transit_hash);
301 transit_hash = NULL;
302}
6b0655a2 303
718e3744 304/* Attribute hash routines. */
9bddac4b 305static struct hash *attrhash;
718e3744 306
fb982c25
PJ
307static struct attr_extra *
308bgp_attr_extra_new (void)
309{
310 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
311}
312
313void
314bgp_attr_extra_free (struct attr *attr)
315{
316 if (attr->extra)
317 {
318 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
319 attr->extra = NULL;
320 }
321}
322
323struct attr_extra *
324bgp_attr_extra_get (struct attr *attr)
325{
326 if (!attr->extra)
327 attr->extra = bgp_attr_extra_new();
328 return attr->extra;
329}
330
331/* Shallow copy of an attribute
332 * Though, not so shallow that it doesn't copy the contents
333 * of the attr_extra pointed to by 'extra'
334 */
335void
336bgp_attr_dup (struct attr *new, struct attr *orig)
337{
558d1fec
JBD
338 struct attr_extra *extra = new->extra;
339
fb982c25 340 *new = *orig;
a0de1d16
CF
341 /* if caller provided attr_extra space, use it in any case.
342 *
343 * This is neccesary even if orig->extra equals NULL, because otherwise
344 * memory may be later allocated on the heap by bgp_attr_extra_get.
345 *
346 * That memory would eventually be leaked, because the caller must not
347 * call bgp_attr_extra_free if he provided attr_extra on the stack.
348 */
349 if (extra)
350 {
351 new->extra = extra;
352 memset(new->extra, 0, sizeof(struct attr_extra));
353 if (orig->extra)
354 *new->extra = *orig->extra;
355 }
356 else if (orig->extra)
fb982c25 357 {
a0de1d16 358 new->extra = bgp_attr_extra_new();
fb982c25
PJ
359 *new->extra = *orig->extra;
360 }
361}
362
73ac8160
DS
363void
364bgp_attr_deep_dup (struct attr *new, struct attr *orig)
365{
366 if (orig->aspath)
367 new->aspath = aspath_dup(orig->aspath);
368
369 if (orig->community)
370 new->community = community_dup(orig->community);
371
372 if (orig->extra)
373 {
374 if (orig->extra->ecommunity)
375 new->extra->ecommunity = ecommunity_dup(orig->extra->ecommunity);
376 if (orig->extra->cluster)
377 new->extra->cluster = cluster_dup(orig->extra->cluster);
378 if (orig->extra->transit)
379 new->extra->transit = transit_dup(orig->extra->transit);
380 }
381}
382
383void
384bgp_attr_deep_free (struct attr *attr)
385{
386 if (attr->aspath)
387 aspath_free(attr->aspath);
388
389 if (attr->community)
390 community_free(attr->community);
391
392 if (attr->extra)
393 {
394 if (attr->extra->ecommunity)
395 ecommunity_free(&attr->extra->ecommunity);
396 if (attr->extra->cluster)
397 cluster_free(attr->extra->cluster);
398 if (attr->extra->transit)
399 transit_free(attr->extra->transit);
400 }
401}
402
cbdfbaa5
PJ
403unsigned long int
404attr_count (void)
405{
406 return attrhash->count;
407}
408
409unsigned long int
410attr_unknown_count (void)
411{
412 return transit_hash->count;
413}
414
718e3744 415unsigned int
923de654 416attrhash_key_make (void *p)
718e3744 417{
7fb0cd82
JBD
418 const struct attr *attr = (struct attr *) p;
419 const struct attr_extra *extra = attr->extra;
c8e7b895
SH
420 uint32_t key = 0;
421#define MIX(val) key = jhash_1word(val, key)
422
423 MIX(attr->origin);
424 MIX(attr->nexthop.s_addr);
425 MIX(attr->med);
426 MIX(attr->local_pref);
718e3744 427
c8f3fe30
PJ
428 key += attr->origin;
429 key += attr->nexthop.s_addr;
430 key += attr->med;
431 key += attr->local_pref;
fb982c25 432
7fb0cd82 433 if (extra)
fb982c25 434 {
7fb0cd82
JBD
435 MIX(extra->aggregator_as);
436 MIX(extra->aggregator_addr.s_addr);
437 MIX(extra->weight);
438 MIX(extra->mp_nexthop_global_in.s_addr);
689bb66c 439 MIX(extra->originator_id.s_addr);
0d9551dc 440 MIX(extra->tag);
fb982c25
PJ
441 }
442
718e3744 443 if (attr->aspath)
c8e7b895 444 MIX(aspath_key_make (attr->aspath));
718e3744 445 if (attr->community)
c8e7b895 446 MIX(community_hash_make (attr->community));
fb982c25 447
7fb0cd82 448 if (extra)
fb982c25 449 {
7fb0cd82
JBD
450 if (extra->ecommunity)
451 MIX(ecommunity_hash_make (extra->ecommunity));
452 if (extra->cluster)
453 MIX(cluster_hash_key_make (extra->cluster));
454 if (extra->transit)
455 MIX(transit_hash_key_make (extra->transit));
718e3744 456
457#ifdef HAVE_IPV6
7fb0cd82 458 MIX(extra->mp_nexthop_len);
801a9bcc
DS
459 key = jhash(extra->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
460 key = jhash(extra->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
718e3744 461#endif /* HAVE_IPV6 */
fb982c25 462 }
718e3744 463
464 return key;
465}
466
467int
ffe11cfb 468attrhash_cmp (const void *p1, const void *p2)
718e3744 469{
ffe11cfb
SH
470 const struct attr * attr1 = p1;
471 const struct attr * attr2 = p2;
923de654 472
718e3744 473 if (attr1->flag == attr2->flag
474 && attr1->origin == attr2->origin
475 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
fb982c25
PJ
476 && attr1->aspath == attr2->aspath
477 && attr1->community == attr2->community
718e3744 478 && attr1->med == attr2->med
3f9c7369
DS
479 && attr1->local_pref == attr2->local_pref
480 && attr1->rmap_change_flags == attr2->rmap_change_flags)
fb982c25 481 {
ffe11cfb
SH
482 const struct attr_extra *ae1 = attr1->extra;
483 const struct attr_extra *ae2 = attr2->extra;
fb982c25
PJ
484
485 if (ae1 && ae2
486 && ae1->aggregator_as == ae2->aggregator_as
487 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
488 && ae1->weight == ae2->weight
0d9551dc 489 && ae1->tag == ae2->tag
718e3744 490#ifdef HAVE_IPV6
fb982c25
PJ
491 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
492 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
493 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
718e3744 494#endif /* HAVE_IPV6 */
fb982c25
PJ
495 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
496 && ae1->ecommunity == ae2->ecommunity
497 && ae1->cluster == ae2->cluster
689bb66c
PM
498 && ae1->transit == ae2->transit
499 && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
fb982c25
PJ
500 return 1;
501 else if (ae1 || ae2)
502 return 0;
503 /* neither attribute has extra attributes, so they're same */
504 return 1;
505 }
718e3744 506 else
507 return 0;
508}
509
94f2b392 510static void
ffe11cfb 511attrhash_init (void)
718e3744 512{
513 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
514}
515
228da428
CC
516static void
517attrhash_finish (void)
518{
519 hash_free (attrhash);
520 attrhash = NULL;
521}
522
94f2b392 523static void
718e3744 524attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
525{
526 struct attr *attr = backet->data;
527
528 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
529 inet_ntoa (attr->nexthop), VTY_NEWLINE);
530}
531
532void
533attr_show_all (struct vty *vty)
534{
535 hash_iterate (attrhash,
536 (void (*)(struct hash_backet *, void *))
537 attr_show_all_iterator,
538 vty);
539}
540
94f2b392 541static void *
923de654 542bgp_attr_hash_alloc (void *p)
718e3744 543{
ffd0c037 544 const struct attr * val = (const struct attr *) p;
718e3744 545 struct attr *attr;
546
547 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
548 *attr = *val;
fb982c25
PJ
549 if (val->extra)
550 {
551 attr->extra = bgp_attr_extra_new ();
552 *attr->extra = *val->extra;
553 }
718e3744 554 attr->refcnt = 0;
555 return attr;
556}
557
558/* Internet argument attribute. */
559struct attr *
560bgp_attr_intern (struct attr *attr)
561{
562 struct attr *find;
563
564 /* Intern referenced strucutre. */
565 if (attr->aspath)
566 {
567 if (! attr->aspath->refcnt)
568 attr->aspath = aspath_intern (attr->aspath);
569 else
570 attr->aspath->refcnt++;
571 }
572 if (attr->community)
573 {
574 if (! attr->community->refcnt)
575 attr->community = community_intern (attr->community);
576 else
577 attr->community->refcnt++;
578 }
fb982c25 579 if (attr->extra)
718e3744 580 {
fb982c25
PJ
581 struct attr_extra *attre = attr->extra;
582
583 if (attre->ecommunity)
584 {
585 if (! attre->ecommunity->refcnt)
586 attre->ecommunity = ecommunity_intern (attre->ecommunity);
587 else
588 attre->ecommunity->refcnt++;
f6f434b2 589
fb982c25
PJ
590 }
591 if (attre->cluster)
592 {
593 if (! attre->cluster->refcnt)
594 attre->cluster = cluster_intern (attre->cluster);
595 else
596 attre->cluster->refcnt++;
597 }
598 if (attre->transit)
599 {
600 if (! attre->transit->refcnt)
601 attre->transit = transit_intern (attre->transit);
602 else
603 attre->transit->refcnt++;
604 }
718e3744 605 }
f6f434b2 606
718e3744 607 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
608 find->refcnt++;
f6f434b2 609
718e3744 610 return find;
611}
612
3f9c7369
DS
613/**
614 * Increment the refcount on various structures that attr holds.
615 * Note on usage: call _only_ when the 'attr' object has already
616 * been 'intern'ed and exists in 'attrhash' table. The function
617 * serves to hold a reference to that (real) object.
618 * Note also that the caller can safely call bgp_attr_unintern()
619 * after calling bgp_attr_refcount(). That would release the
620 * reference and could result in a free() of the attr object.
621 */
622struct attr *
623bgp_attr_refcount (struct attr *attr)
624{
625 /* Intern referenced strucutre. */
626 if (attr->aspath)
627 attr->aspath->refcnt++;
628
629 if (attr->community)
630 attr->community->refcnt++;
631
632 if (attr->extra)
633 {
634 struct attr_extra *attre = attr->extra;
635 if (attre->ecommunity)
636 attre->ecommunity->refcnt++;
637
638 if (attre->cluster)
639 attre->cluster->refcnt++;
640
641 if (attre->transit)
642 attre->transit->refcnt++;
643 }
644 attr->refcnt++;
645 return attr;
646}
03e214c8 647
718e3744 648/* Make network statement's attribute. */
649struct attr *
650bgp_attr_default_set (struct attr *attr, u_char origin)
651{
652 memset (attr, 0, sizeof (struct attr));
fb982c25
PJ
653 bgp_attr_extra_get (attr);
654
718e3744 655 attr->origin = origin;
656 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
657 attr->aspath = aspath_empty ();
658 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
fb982c25 659 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
0d9551dc 660 attr->extra->tag = 0;
718e3744 661 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
662#ifdef HAVE_IPV6
fb982c25 663 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
718e3744 664#endif
03e214c8 665
718e3744 666 return attr;
667}
668
03e214c8 669
718e3744 670/* Make network statement's attribute. */
671struct attr *
672bgp_attr_default_intern (u_char origin)
673{
674 struct attr attr;
675 struct attr *new;
e16a4133 676
03e214c8 677 bgp_attr_default_set(&attr, origin);
718e3744 678
679 new = bgp_attr_intern (&attr);
fb982c25
PJ
680 bgp_attr_extra_free (&attr);
681
f6f434b2 682 aspath_unintern (&new->aspath);
718e3744 683 return new;
684}
685
b5d58c32 686/* Create the attributes for an aggregate */
718e3744 687struct attr *
688bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
689 struct aspath *aspath,
42f7e184
DS
690 struct community *community, int as_set,
691 u_char atomic_aggregate)
718e3744 692{
693 struct attr attr;
694 struct attr *new;
938ef3a2 695 struct attr_extra attre;
718e3744 696
697 memset (&attr, 0, sizeof (struct attr));
938ef3a2
JBD
698 memset (&attre, 0, sizeof (struct attr_extra));
699 attr.extra = &attre;
700
718e3744 701 /* Origin attribute. */
702 attr.origin = origin;
703 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
704
705 /* AS path attribute. */
706 if (aspath)
707 attr.aspath = aspath_intern (aspath);
708 else
709 attr.aspath = aspath_empty ();
710 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
711
712 /* Next hop attribute. */
713 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
714
715 if (community)
716 {
717 attr.community = community;
718 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
719 }
720
938ef3a2 721 attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
718e3744 722#ifdef HAVE_IPV6
938ef3a2 723 attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
718e3744 724#endif
42f7e184 725 if (! as_set || atomic_aggregate)
718e3744 726 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
727 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
728 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
938ef3a2 729 attre.aggregator_as = bgp->confed_id;
718e3744 730 else
938ef3a2
JBD
731 attre.aggregator_as = bgp->as;
732 attre.aggregator_addr = bgp->router_id;
718e3744 733
734 new = bgp_attr_intern (&attr);
938ef3a2 735
f6f434b2 736 aspath_unintern (&new->aspath);
718e3744 737 return new;
738}
739
b881c707
PJ
740/* Unintern just the sub-components of the attr, but not the attr */
741void
742bgp_attr_unintern_sub (struct attr *attr)
743{
744 /* aspath refcount shoud be decrement. */
745 if (attr->aspath)
746 aspath_unintern (&attr->aspath);
d92a2f39 747 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH));
b881c707
PJ
748
749 if (attr->community)
750 community_unintern (&attr->community);
d92a2f39 751 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
b881c707
PJ
752
753 if (attr->extra)
754 {
755 if (attr->extra->ecommunity)
756 ecommunity_unintern (&attr->extra->ecommunity);
d92a2f39 757 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
b881c707
PJ
758
759 if (attr->extra->cluster)
760 cluster_unintern (attr->extra->cluster);
d92a2f39 761 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
b881c707
PJ
762
763 if (attr->extra->transit)
764 transit_unintern (attr->extra->transit);
765 }
766}
767
718e3744 768/* Free bgp attribute and aspath. */
769void
1a2fd707 770bgp_attr_unintern (struct attr **pattr)
718e3744 771{
1a2fd707 772 struct attr *attr = *pattr;
718e3744 773 struct attr *ret;
b881c707 774 struct attr tmp;
b9f1dca1 775 struct attr_extra tmp_extra;
f6f434b2 776
718e3744 777 /* Decrement attribute reference. */
1a2fd707 778 attr->refcnt--;
b881c707 779
1a2fd707 780 tmp = *attr;
b881c707 781
1a2fd707 782 if (attr->extra)
fb982c25 783 {
b9f1dca1 784 tmp.extra = &tmp_extra;
1a2fd707 785 memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
fb982c25 786 }
f6f434b2 787
718e3744 788 /* If reference becomes zero then free attribute object. */
1a2fd707
JBD
789 if (attr->refcnt == 0)
790 {
791 ret = hash_release (attrhash, attr);
718e3744 792 assert (ret != NULL);
1a2fd707
JBD
793 bgp_attr_extra_free (attr);
794 XFREE (MTYPE_ATTR, attr);
795 *pattr = NULL;
718e3744 796 }
797
b881c707 798 bgp_attr_unintern_sub (&tmp);
718e3744 799}
800
801void
802bgp_attr_flush (struct attr *attr)
803{
804 if (attr->aspath && ! attr->aspath->refcnt)
805 aspath_free (attr->aspath);
806 if (attr->community && ! attr->community->refcnt)
807 community_free (attr->community);
fb982c25
PJ
808 if (attr->extra)
809 {
810 struct attr_extra *attre = attr->extra;
f6f434b2 811
fb982c25 812 if (attre->ecommunity && ! attre->ecommunity->refcnt)
f6f434b2 813 ecommunity_free (&attre->ecommunity);
fb982c25
PJ
814 if (attre->cluster && ! attre->cluster->refcnt)
815 cluster_free (attre->cluster);
816 if (attre->transit && ! attre->transit->refcnt)
817 transit_free (attre->transit);
818 }
718e3744 819}
820
b881c707
PJ
821/* Implement draft-scudder-idr-optional-transitive behaviour and
822 * avoid resetting sessions for malformed attributes which are
823 * are partial/optional and hence where the error likely was not
824 * introduced by the sending neighbour.
825 */
826static bgp_attr_parse_ret_t
835315bf
PJ
827bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
828 bgp_size_t length)
b881c707 829{
835315bf
PJ
830 struct peer *const peer = args->peer;
831 const u_int8_t flags = args->flags;
832 /* startp and length must be special-cased, as whether or not to
833 * send the attribute data with the NOTIFY depends on the error,
834 * the caller therefore signals this with the seperate length argument
835 */
bd471fea 836 u_char *notify_datap = (length > 0 ? args->startp : NULL);
835315bf 837
b881c707 838 /* Only relax error handling for eBGP peers */
6d85b15b 839 if (peer->sort != BGP_PEER_EBGP)
b881c707
PJ
840 {
841 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
bd471fea 842 notify_datap, length);
b881c707
PJ
843 return BGP_ATTR_PARSE_ERROR;
844
845 }
846
bd471fea
PJ
847 /* Adjust the stream getp to the end of the attribute, in case we can
848 * still proceed but the caller hasn't read all the attribute.
849 */
850 stream_set_getp (BGP_INPUT (peer),
851 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
852 + args->total);
853
835315bf 854 switch (args->type) {
fa61e16d
PJ
855 /* where an attribute is relatively inconsequential, e.g. it does not
856 * affect route selection, and can be safely ignored, then any such
857 * attributes which are malformed should just be ignored and the route
858 * processed as normal.
b881c707
PJ
859 */
860 case BGP_ATTR_AS4_AGGREGATOR:
861 case BGP_ATTR_AGGREGATOR:
862 case BGP_ATTR_ATOMIC_AGGREGATE:
863 return BGP_ATTR_PARSE_PROCEED;
864
865 /* Core attributes, particularly ones which may influence route
fa61e16d 866 * selection, should always cause session resets
b881c707
PJ
867 */
868 case BGP_ATTR_ORIGIN:
869 case BGP_ATTR_AS_PATH:
870 case BGP_ATTR_NEXT_HOP:
871 case BGP_ATTR_MULTI_EXIT_DISC:
872 case BGP_ATTR_LOCAL_PREF:
873 case BGP_ATTR_COMMUNITIES:
874 case BGP_ATTR_ORIGINATOR_ID:
875 case BGP_ATTR_CLUSTER_LIST:
876 case BGP_ATTR_MP_REACH_NLRI:
877 case BGP_ATTR_MP_UNREACH_NLRI:
878 case BGP_ATTR_EXT_COMMUNITIES:
879 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
bd471fea 880 notify_datap, length);
b881c707
PJ
881 return BGP_ATTR_PARSE_ERROR;
882 }
883
884 /* Partial optional attributes that are malformed should not cause
885 * the whole session to be reset. Instead treat it as a withdrawal
886 * of the routes, if possible.
887 */
835315bf
PJ
888 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
889 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
890 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
b881c707
PJ
891 return BGP_ATTR_PARSE_WITHDRAW;
892
893 /* default to reset */
f57000c0 894 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
b881c707
PJ
895}
896
afcb7679
DO
897/* Find out what is wrong with the path attribute flag bits and log the error.
898 "Flag bits" here stand for Optional, Transitive and Partial, but not for
899 Extended Length. Checking O/T/P bits at once implies, that the attribute
900 being diagnosed is defined by RFC as either a "well-known" or an "optional,
901 non-transitive" attribute. */
902static void
835315bf
PJ
903bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
904 u_int8_t desired_flags /* how RFC says it must be */
afcb7679
DO
905)
906{
907 u_char seen = 0, i;
835315bf
PJ
908 u_char real_flags = args->flags;
909 const u_int8_t attr_code = args->type;
910
afcb7679
DO
911 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
912 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
913 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
914 if
915 (
916 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
917 CHECK_FLAG (real_flags, attr_flag_str[i].key)
918 )
919 {
16286195
DS
920 zlog_err ("%s attribute must%s be flagged as \"%s\"",
921 LOOKUP (attr_str, attr_code),
922 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
923 attr_flag_str[i].str);
afcb7679
DO
924 seen = 1;
925 }
fa5831e8
PJ
926 if (!seen)
927 {
16286195
DS
928 zlog_debug ("Strange, %s called for attr %s, but no problem found with flags"
929 " (real flags 0x%x, desired 0x%x)",
930 __func__, LOOKUP (attr_str, attr_code),
931 real_flags, desired_flags);
fa5831e8 932 }
afcb7679
DO
933}
934
3ecab4c8
PJ
935/* Required flags for attributes. EXTLEN will be masked off when testing,
936 * as will PARTIAL for optional+transitive attributes.
937 */
938const u_int8_t attr_flags_values [] = {
939 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
940 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
941 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
942 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
943 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
944 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
945 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
946 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
947 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
948 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
949 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
950 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
951 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
952 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
953 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
954};
955static const size_t attr_flags_values_max =
956 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
957
958static int
835315bf 959bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
3ecab4c8
PJ
960{
961 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
835315bf
PJ
962 const u_int8_t flags = args->flags;
963 const u_int8_t attr_code = args->type;
3ecab4c8
PJ
964
965 /* there may be attributes we don't know about */
966 if (attr_code > attr_flags_values_max)
967 return 0;
968 if (attr_flags_values[attr_code] == 0)
969 return 0;
970
971 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
972 * 1."
973 */
974 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
975 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
976 {
16286195
DS
977 zlog_err ("%s well-known attributes must have transitive flag set (%x)",
978 LOOKUP (attr_str, attr_code), flags);
3ecab4c8
PJ
979 return 1;
980 }
981
982 /* "For well-known attributes and for optional non-transitive attributes,
983 * the Partial bit MUST be set to 0."
984 */
985 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
986 {
987 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
988 {
16286195
DS
989 zlog_err ("%s well-known attribute "
990 "must NOT have the partial flag set (%x)",
991 LOOKUP (attr_str, attr_code), flags);
3ecab4c8
PJ
992 return 1;
993 }
994 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
995 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
996 {
16286195
DS
997 zlog_err ("%s optional + transitive attribute "
998 "must NOT have the partial flag set (%x)",
999 LOOKUP (attr_str, attr_code), flags);
3ecab4c8
PJ
1000 return 1;
1001 }
1002 }
1003
1004 /* Optional transitive attributes may go through speakers that don't
1005 * reocgnise them and set the Partial bit.
1006 */
1007 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
1008 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
1009 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
1010
683f2b86 1011 if ((flags & ~mask)
3ecab4c8
PJ
1012 == attr_flags_values[attr_code])
1013 return 0;
1014
835315bf 1015 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
3ecab4c8
PJ
1016 return 1;
1017}
1018
718e3744 1019/* Get origin attribute of the update message. */
b881c707 1020static bgp_attr_parse_ret_t
835315bf 1021bgp_attr_origin (struct bgp_attr_parser_args *args)
718e3744 1022{
835315bf
PJ
1023 struct peer *const peer = args->peer;
1024 struct attr *const attr = args->attr;
1025 const bgp_size_t length = args->length;
1026
718e3744 1027 /* If any recognized attribute has Attribute Length that conflicts
1028 with the expected length (based on the attribute type code), then
1029 the Error Subcode is set to Attribute Length Error. The Data
1030 field contains the erroneous attribute (type, length and
1031 value). */
1032 if (length != 1)
1033 {
16286195 1034 zlog_err ("Origin attribute length is not one %d", length);
835315bf 1035 return bgp_attr_malformed (args,
b881c707 1036 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1037 args->total);
718e3744 1038 }
1039
1040 /* Fetch origin attribute. */
1041 attr->origin = stream_getc (BGP_INPUT (peer));
1042
1043 /* If the ORIGIN attribute has an undefined value, then the Error
1044 Subcode is set to Invalid Origin Attribute. The Data field
1045 contains the unrecognized attribute (type, length and value). */
1046 if ((attr->origin != BGP_ORIGIN_IGP)
1047 && (attr->origin != BGP_ORIGIN_EGP)
1048 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
1049 {
16286195 1050 zlog_err ("Origin attribute value is invalid %d", attr->origin);
835315bf 1051 return bgp_attr_malformed (args,
b881c707 1052 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
835315bf 1053 args->total);
718e3744 1054 }
1055
1056 /* Set oring attribute flag. */
1057 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
1058
1059 return 0;
1060}
ab005298
PJ
1061
1062/* Parse AS path information. This function is wrapper of
1063 aspath_parse. */
1064static int
835315bf 1065bgp_attr_aspath (struct bgp_attr_parser_args *args)
718e3744 1066{
835315bf
PJ
1067 struct attr *const attr = args->attr;
1068 struct peer *const peer = args->peer;
1069 const bgp_size_t length = args->length;
3ecab4c8 1070
ab005298
PJ
1071 /*
1072 * peer with AS4 => will get 4Byte ASnums
1073 * otherwise, will get 16 Bit
0b2aa3a0 1074 */
ab005298
PJ
1075 attr->aspath = aspath_parse (peer->ibuf, length,
1076 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
0b2aa3a0 1077
ab005298
PJ
1078 /* In case of IBGP, length will be zero. */
1079 if (! attr->aspath)
cddb8112 1080 {
16286195 1081 zlog_err ("Malformed AS path from %s, length is %d", peer->host, length);
835315bf 1082 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
cddb8112 1083 }
cddb8112 1084
ab005298
PJ
1085 /* Set aspath attribute flag. */
1086 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
0b2aa3a0 1087
b881c707 1088 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1089}
1090
b881c707 1091static bgp_attr_parse_ret_t
835315bf 1092bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
0b2aa3a0
PJ
1093{
1094 /* These checks were part of bgp_attr_aspath, but with
1095 * as4 we should to check aspath things when
1096 * aspath synthesizing with as4_path has already taken place.
1097 * Otherwise we check ASPATH and use the synthesized thing, and that is
1098 * not right.
1099 * So do the checks later, i.e. here
1100 */
1101 struct bgp *bgp = peer->bgp;
1102 struct aspath *aspath;
1103
ca87e1d3 1104 /* Confederation sanity check. */
6d85b15b
JBD
1105 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1106 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
ca87e1d3 1107 {
16286195 1108 zlog_err ("Malformed AS path from %s", peer->host);
835315bf
PJ
1109 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1110 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1111 return BGP_ATTR_PARSE_ERROR;
ca87e1d3
VT
1112 }
1113
718e3744 1114 /* First AS check for EBGP. */
1115 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1116 {
6d85b15b 1117 if (peer->sort == BGP_PEER_EBGP
718e3744 1118 && ! aspath_firstas_check (attr->aspath, peer->as))
1119 {
16286195 1120 zlog_err ("%s incorrect first AS (must be %u)", peer->host, peer->as);
835315bf
PJ
1121 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1122 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1123 return BGP_ATTR_PARSE_ERROR;
718e3744 1124 }
1125 }
1126
1127 /* local-as prepend */
1128 if (peer->change_local_as &&
1129 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1130 {
1131 aspath = aspath_dup (attr->aspath);
1132 aspath = aspath_add_seq (aspath, peer->change_local_as);
f6f434b2 1133 aspath_unintern (&attr->aspath);
718e3744 1134 attr->aspath = aspath_intern (aspath);
1135 }
1136
b881c707 1137 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1138}
1139
ab005298
PJ
1140/* Parse AS4 path information. This function is another wrapper of
1141 aspath_parse. */
1142static int
835315bf 1143bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
ab005298 1144{
835315bf
PJ
1145 struct peer *const peer = args->peer;
1146 struct attr *const attr = args->attr;
1147 const bgp_size_t length = args->length;
3ecab4c8 1148
ab005298
PJ
1149 *as4_path = aspath_parse (peer->ibuf, length, 1);
1150
b881c707
PJ
1151 /* In case of IBGP, length will be zero. */
1152 if (!*as4_path)
1153 {
16286195 1154 zlog_err ("Malformed AS4 path from %s, length is %d", peer->host, length);
835315bf 1155 return bgp_attr_malformed (args,
b881c707 1156 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
835315bf 1157 0);
b881c707
PJ
1158 }
1159
ab005298
PJ
1160 /* Set aspath attribute flag. */
1161 if (as4_path)
1162 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1163
b881c707 1164 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1165}
1166
718e3744 1167/* Nexthop attribute. */
b881c707 1168static bgp_attr_parse_ret_t
835315bf 1169bgp_attr_nexthop (struct bgp_attr_parser_args *args)
718e3744 1170{
835315bf
PJ
1171 struct peer *const peer = args->peer;
1172 struct attr *const attr = args->attr;
1173 const bgp_size_t length = args->length;
1174
bc3443eb 1175 in_addr_t nexthop_h, nexthop_n;
718e3744 1176
718e3744 1177 /* Check nexthop attribute length. */
1178 if (length != 4)
1179 {
16286195 1180 zlog_err ("Nexthop attribute length isn't four [%d]", length);
718e3744 1181
835315bf 1182 return bgp_attr_malformed (args,
b881c707 1183 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1184 args->total);
718e3744 1185 }
1186
58298ccd
DS
1187 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1188 attribute must result in a NOTIFICATION message (this is implemented below).
1189 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1190 logged locally (this is implemented somewhere else). The UPDATE message
1191 gets ignored in any of these cases. */
bc3443eb
DO
1192 nexthop_n = stream_get_ipv4 (peer->ibuf);
1193 nexthop_h = ntohl (nexthop_n);
58298ccd 1194 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
bc3443eb
DO
1195 {
1196 char buf[INET_ADDRSTRLEN];
bb02b823 1197 inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
16286195 1198 zlog_err ("Martian nexthop %s", buf);
835315bf 1199 return bgp_attr_malformed (args,
bc3443eb 1200 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
835315bf 1201 args->total);
bc3443eb
DO
1202 }
1203
1204 attr->nexthop.s_addr = nexthop_n;
718e3744 1205 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1206
b881c707 1207 return BGP_ATTR_PARSE_PROCEED;
718e3744 1208}
1209
1210/* MED atrribute. */
b881c707 1211static bgp_attr_parse_ret_t
835315bf 1212bgp_attr_med (struct bgp_attr_parser_args *args)
718e3744 1213{
835315bf
PJ
1214 struct peer *const peer = args->peer;
1215 struct attr *const attr = args->attr;
1216 const bgp_size_t length = args->length;
1217
718e3744 1218 /* Length check. */
1219 if (length != 4)
1220 {
16286195 1221 zlog_err ("MED attribute length isn't four [%d]", length);
b881c707 1222
835315bf 1223 return bgp_attr_malformed (args,
b881c707 1224 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1225 args->total);
718e3744 1226 }
1227
1228 attr->med = stream_getl (peer->ibuf);
1229
1230 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1231
b881c707 1232 return BGP_ATTR_PARSE_PROCEED;
718e3744 1233}
1234
1235/* Local preference attribute. */
b881c707 1236static bgp_attr_parse_ret_t
835315bf 1237bgp_attr_local_pref (struct bgp_attr_parser_args *args)
718e3744 1238{
835315bf
PJ
1239 struct peer *const peer = args->peer;
1240 struct attr *const attr = args->attr;
1241 const bgp_size_t length = args->length;
3ecab4c8 1242
a624cae2
DO
1243 /* Length check. */
1244 if (length != 4)
1245 {
16286195 1246 zlog_err ("LOCAL_PREF attribute length isn't 4 [%u]", length);
835315bf 1247 return bgp_attr_malformed (args,
a624cae2 1248 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1249 args->total);
a624cae2 1250 }
0ea968d2 1251
718e3744 1252 /* If it is contained in an UPDATE message that is received from an
1253 external peer, then this attribute MUST be ignored by the
1254 receiving speaker. */
6d85b15b 1255 if (peer->sort == BGP_PEER_EBGP)
718e3744 1256 {
9985f83c 1257 stream_forward_getp (peer->ibuf, length);
b881c707 1258 return BGP_ATTR_PARSE_PROCEED;
718e3744 1259 }
1260
a624cae2 1261 attr->local_pref = stream_getl (peer->ibuf);
718e3744 1262
1263 /* Set atomic aggregate flag. */
1264 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1265
b881c707 1266 return BGP_ATTR_PARSE_PROCEED;
718e3744 1267}
1268
1269/* Atomic aggregate. */
94f2b392 1270static int
835315bf 1271bgp_attr_atomic (struct bgp_attr_parser_args *args)
718e3744 1272{
835315bf
PJ
1273 struct attr *const attr = args->attr;
1274 const bgp_size_t length = args->length;
3ecab4c8 1275
9eba2ada 1276 /* Length check. */
718e3744 1277 if (length != 0)
1278 {
16286195 1279 zlog_err ("ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
835315bf 1280 return bgp_attr_malformed (args,
b881c707 1281 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1282 args->total);
718e3744 1283 }
1284
1285 /* Set atomic aggregate flag. */
1286 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1287
b881c707 1288 return BGP_ATTR_PARSE_PROCEED;
718e3744 1289}
1290
1291/* Aggregator attribute */
94f2b392 1292static int
835315bf 1293bgp_attr_aggregator (struct bgp_attr_parser_args *args)
718e3744 1294{
835315bf
PJ
1295 struct peer *const peer = args->peer;
1296 struct attr *const attr = args->attr;
1297 const bgp_size_t length = args->length;
1298
0b2aa3a0 1299 int wantedlen = 6;
fb982c25 1300 struct attr_extra *attre = bgp_attr_extra_get (attr);
3ecab4c8 1301
0b2aa3a0 1302 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
b881c707 1303 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
0b2aa3a0
PJ
1304 wantedlen = 8;
1305
1306 if (length != wantedlen)
718e3744 1307 {
16286195 1308 zlog_err ("AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
835315bf 1309 return bgp_attr_malformed (args,
b881c707 1310 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1311 args->total);
718e3744 1312 }
0b2aa3a0
PJ
1313
1314 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1315 attre->aggregator_as = stream_getl (peer->ibuf);
1316 else
1317 attre->aggregator_as = stream_getw (peer->ibuf);
fb982c25 1318 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
718e3744 1319
1320 /* Set atomic aggregate flag. */
1321 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1322
b881c707 1323 return BGP_ATTR_PARSE_PROCEED;
718e3744 1324}
1325
0b2aa3a0 1326/* New Aggregator attribute */
b881c707 1327static bgp_attr_parse_ret_t
835315bf
PJ
1328bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1329 as_t *as4_aggregator_as,
1330 struct in_addr *as4_aggregator_addr)
0b2aa3a0 1331{
835315bf
PJ
1332 struct peer *const peer = args->peer;
1333 struct attr *const attr = args->attr;
1334 const bgp_size_t length = args->length;
1335
0b2aa3a0
PJ
1336 if (length != 8)
1337 {
16286195 1338 zlog_err ("New Aggregator length is not 8 [%d]", length);
835315bf 1339 return bgp_attr_malformed (args,
b881c707 1340 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1341 0);
0b2aa3a0 1342 }
3ecab4c8 1343
0b2aa3a0
PJ
1344 *as4_aggregator_as = stream_getl (peer->ibuf);
1345 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1346
1347 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1348
b881c707 1349 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1350}
1351
1352/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1353 */
b881c707 1354static bgp_attr_parse_ret_t
835315bf
PJ
1355bgp_attr_munge_as4_attrs (struct peer *const peer,
1356 struct attr *const attr,
0b2aa3a0
PJ
1357 struct aspath *as4_path, as_t as4_aggregator,
1358 struct in_addr *as4_aggregator_addr)
1359{
1360 int ignore_as4_path = 0;
1361 struct aspath *newpath;
1362 struct attr_extra *attre = attr->extra;
1363
b881c707 1364 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
0b2aa3a0
PJ
1365 {
1366 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1367 * if given.
1368 * It is worth a warning though, because the peer really
1369 * should not send them
1370 */
1371 if (BGP_DEBUG(as4, AS4))
1372 {
1373 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1374 zlog_debug ("[AS4] %s %s AS4_PATH",
1375 peer->host, "AS4 capable peer, yet it sent");
1376
1377 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1378 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1379 peer->host, "AS4 capable peer, yet it sent");
1380 }
1381
b881c707 1382 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1383 }
1384
0b2aa3a0
PJ
1385 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1386 * because that may override AS4_PATH
1387 */
1388 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1389 {
b881c707 1390 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
0b2aa3a0 1391 {
370b64a2
PJ
1392 assert (attre);
1393
0b2aa3a0
PJ
1394 /* received both.
1395 * if the as_number in aggregator is not AS_TRANS,
1396 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1397 * and the Aggregator shall be taken as
1398 * info on the aggregating node, and the AS_PATH
1399 * shall be taken as the AS_PATH
1400 * otherwise
1401 * the Aggregator shall be ignored and the
1402 * AS4_AGGREGATOR shall be taken as the
1403 * Aggregating node and the AS_PATH is to be
1404 * constructed "as in all other cases"
1405 */
b881c707 1406 if (attre->aggregator_as != BGP_AS_TRANS)
0b2aa3a0
PJ
1407 {
1408 /* ignore */
1409 if ( BGP_DEBUG(as4, AS4))
1410 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1411 " send AGGREGATOR != AS_TRANS and"
1412 " AS4_AGGREGATOR, so ignore"
1413 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1414 ignore_as4_path = 1;
1415 }
1416 else
1417 {
1418 /* "New_aggregator shall be taken as aggregator" */
1419 attre->aggregator_as = as4_aggregator;
1420 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1421 }
1422 }
1423 else
1424 {
1425 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1426 * That is bogus - but reading the conditions
1427 * we have to handle AS4_AGGREGATOR as if it were
1428 * AGGREGATOR in that case
1429 */
1430 if ( BGP_DEBUG(as4, AS4))
1431 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1432 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1433 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
370b64a2 1434 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
0b2aa3a0
PJ
1435 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1436 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1437 }
1438 }
1439
1440 /* need to reconcile NEW_AS_PATH and AS_PATH */
b881c707 1441 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
0b2aa3a0 1442 {
f47e5a18
DL
1443 if (!attr->aspath)
1444 return BGP_ATTR_PARSE_PROCEED;
1445
0b2aa3a0 1446 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
f6f434b2 1447 aspath_unintern (&attr->aspath);
0b2aa3a0
PJ
1448 attr->aspath = aspath_intern (newpath);
1449 }
b881c707 1450 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1451}
1452
718e3744 1453/* Community attribute. */
b881c707 1454static bgp_attr_parse_ret_t
835315bf 1455bgp_attr_community (struct bgp_attr_parser_args *args)
718e3744 1456{
835315bf
PJ
1457 struct peer *const peer = args->peer;
1458 struct attr *const attr = args->attr;
1459 const bgp_size_t length = args->length;
b881c707 1460
718e3744 1461 if (length == 0)
b2ceea18
PJ
1462 {
1463 attr->community = NULL;
b881c707 1464 return BGP_ATTR_PARSE_PROCEED;
b2ceea18 1465 }
0c466381
PJ
1466
1467 attr->community =
1468 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1469
1470 /* XXX: fix community_parse to use stream API and remove this */
1471 stream_forward_getp (peer->ibuf, length);
718e3744 1472
0c466381 1473 if (!attr->community)
835315bf 1474 return bgp_attr_malformed (args,
b881c707 1475 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
835315bf 1476 args->total);
0c466381 1477
718e3744 1478 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1479
b881c707 1480 return BGP_ATTR_PARSE_PROCEED;
718e3744 1481}
1482
1483/* Originator ID attribute. */
b881c707 1484static bgp_attr_parse_ret_t
835315bf 1485bgp_attr_originator_id (struct bgp_attr_parser_args *args)
718e3744 1486{
835315bf
PJ
1487 struct peer *const peer = args->peer;
1488 struct attr *const attr = args->attr;
1489 const bgp_size_t length = args->length;
1490
d595b566 1491 /* Length check. */
718e3744 1492 if (length != 4)
1493 {
16286195 1494 zlog_err ("Bad originator ID length %d", length);
718e3744 1495
835315bf 1496 return bgp_attr_malformed (args,
b881c707 1497 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1498 args->total);
718e3744 1499 }
1500
fb982c25
PJ
1501 (bgp_attr_extra_get (attr))->originator_id.s_addr
1502 = stream_get_ipv4 (peer->ibuf);
718e3744 1503
1504 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1505
b881c707 1506 return BGP_ATTR_PARSE_PROCEED;
718e3744 1507}
1508
1509/* Cluster list attribute. */
b881c707 1510static bgp_attr_parse_ret_t
835315bf 1511bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
718e3744 1512{
835315bf
PJ
1513 struct peer *const peer = args->peer;
1514 struct attr *const attr = args->attr;
1515 const bgp_size_t length = args->length;
1516
718e3744 1517 /* Check length. */
1518 if (length % 4)
1519 {
16286195 1520 zlog_err ("Bad cluster list length %d", length);
718e3744 1521
835315bf
PJ
1522 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1523 args->total);
718e3744 1524 }
1525
fb982c25
PJ
1526 (bgp_attr_extra_get (attr))->cluster
1527 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
b881c707
PJ
1528
1529 /* XXX: Fix cluster_parse to use stream API and then remove this */
1530 stream_forward_getp (peer->ibuf, length);
718e3744 1531
1532 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1533
b881c707 1534 return BGP_ATTR_PARSE_PROCEED;
718e3744 1535}
1536
1537/* Multiprotocol reachability information parse. */
03292809 1538int
835315bf
PJ
1539bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1540 struct bgp_nlri *mp_update)
718e3744 1541{
4c9641ba
ML
1542 afi_t afi;
1543 safi_t safi;
718e3744 1544 bgp_size_t nlri_len;
6e4ab12f 1545 size_t start;
718e3744 1546 int ret;
d889623f 1547 int num_mp_pfx = 0;
718e3744 1548 struct stream *s;
835315bf
PJ
1549 struct peer *const peer = args->peer;
1550 struct attr *const attr = args->attr;
1551 const bgp_size_t length = args->length;
fb982c25 1552 struct attr_extra *attre = bgp_attr_extra_get(attr);
835315bf 1553
718e3744 1554 /* Set end of packet. */
6e4ab12f
PJ
1555 s = BGP_INPUT(peer);
1556 start = stream_get_getp(s);
1557
1558 /* safe to read statically sized header? */
1559#define BGP_MP_REACH_MIN_SIZE 5
03292809 1560#define LEN_LEFT (length - (stream_get_getp(s) - start))
6e4ab12f 1561 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
03292809
PJ
1562 {
1563 zlog_info ("%s: %s sent invalid length, %lu",
1564 __func__, peer->host, (unsigned long)length);
f57000c0 1565 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1566 }
6e4ab12f 1567
718e3744 1568 /* Load AFI, SAFI. */
1569 afi = stream_getw (s);
1570 safi = stream_getc (s);
1571
1572 /* Get nexthop length. */
fb982c25 1573 attre->mp_nexthop_len = stream_getc (s);
6e4ab12f 1574
03292809
PJ
1575 if (LEN_LEFT < attre->mp_nexthop_len)
1576 {
1577 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1578 __func__, peer->host, attre->mp_nexthop_len);
f57000c0 1579 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1580 }
6e4ab12f 1581
718e3744 1582 /* Nexthop length check. */
fb982c25 1583 switch (attre->mp_nexthop_len)
718e3744 1584 {
801a9bcc
DS
1585 case BGP_ATTR_NHLEN_IPV4:
1586 stream_get (&attre->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
66bed4f4
ML
1587 /* Probably needed for RFC 2283 */
1588 if (attr->nexthop.s_addr == 0)
801a9bcc 1589 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
718e3744 1590 break;
801a9bcc 1591 case BGP_ATTR_NHLEN_VPNV4:
9206f9ec
SH
1592 stream_getl (s); /* RD high */
1593 stream_getl (s); /* RD low */
801a9bcc 1594 stream_get (&attre->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
718e3744 1595 break;
1596#ifdef HAVE_IPV6
801a9bcc
DS
1597 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
1598 stream_get (&attre->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
718e3744 1599 break;
801a9bcc
DS
1600 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
1601 stream_get (&attre->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
1602 stream_get (&attre->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
fb982c25 1603 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
718e3744 1604 {
1605 char buf1[INET6_ADDRSTRLEN];
1606 char buf2[INET6_ADDRSTRLEN];
1607
3f9c7369 1608 if (bgp_debug_update(peer, NULL, NULL, 1))
16286195 1609 zlog_debug ("%s sent two nexthops %s %s but second one is not a link-local nexthop", 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
2108bgp_attr_check (struct peer *peer, struct attr *attr)
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
2118 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2119 type = BGP_ATTR_NEXT_HOP;
2120
6d85b15b 2121 if (peer->sort == BGP_PEER_IBGP
718e3744 2122 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2123 type = BGP_ATTR_LOCAL_PREF;
2124
2125 if (type)
2126 {
16286195 2127 zlog_warn ("%s Missing well-known attribute %d.", peer->host, type);
718e3744 2128 bgp_notify_send_with_data (peer,
2129 BGP_NOTIFY_UPDATE_ERR,
2130 BGP_NOTIFY_UPDATE_MISS_ATTR,
2131 &type, 1);
b881c707 2132 return BGP_ATTR_PARSE_ERROR;
718e3744 2133 }
b881c707 2134 return BGP_ATTR_PARSE_PROCEED;
718e3744 2135}
6b0655a2 2136
718e3744 2137int stream_put_prefix (struct stream *, struct prefix *);
2138
8c71e481
PM
2139size_t
2140bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
3f9c7369 2141 struct bpacket_attr_vec_arr *vecarr,
8c71e481
PM
2142 struct attr *attr)
2143{
2144 size_t sizep;
2145
2146 /* Set extended bit always to encode the attribute length as 2 bytes */
2147 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2148 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2149 sizep = stream_get_endp (s);
2150 stream_putw (s, 0); /* Marker: Attribute length. */
2151 stream_putw (s, afi); /* AFI */
2152 stream_putc (s, safi); /* SAFI */
2153
2154 /* Nexthop */
2155 switch (afi)
2156 {
2157 case AFI_IP:
2158 switch (safi)
2159 {
2160 case SAFI_UNICAST:
2161 case SAFI_MULTICAST:
3f9c7369 2162 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
8c71e481
PM
2163 stream_putc (s, 4);
2164 stream_put_ipv4 (s, attr->nexthop.s_addr);
2165 break;
2166 case SAFI_MPLS_VPN:
3f9c7369 2167 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
8c71e481
PM
2168 stream_putc (s, 12);
2169 stream_putl (s, 0);
2170 stream_putl (s, 0);
2171 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
2172 break;
2173 default:
2174 break;
2175 }
2176 break;
2177#ifdef HAVE_IPV6
2178 case AFI_IP6:
2179 switch (safi)
2180 {
2181 case SAFI_UNICAST:
2182 case SAFI_MULTICAST:
2183 {
8c71e481
PM
2184 struct attr_extra *attre = attr->extra;
2185
2186 assert (attr->extra);
3f9c7369 2187 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
8c71e481 2188 stream_putc (s, attre->mp_nexthop_len);
801a9bcc
DS
2189 stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
2190 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
2191 stream_put (s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN);
8c71e481
PM
2192 }
2193 default:
2194 break;
2195 }
2196 break;
2197#endif /*HAVE_IPV6*/
2198 default:
2199 break;
2200 }
2201
2202 /* SNPA */
2203 stream_putc (s, 0);
2204 return sizep;
2205}
2206
2207void
2208bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
2209 struct prefix *p, struct prefix_rd *prd,
2210 u_char *tag)
2211{
2212 switch (safi)
2213 {
2214 case SAFI_MPLS_VPN:
2215 /* Tag, RD, Prefix write. */
2216 stream_putc (s, p->prefixlen + 88);
2217 stream_put (s, tag, 3);
2218 stream_put (s, prd->val, 8);
2219 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2220 break;
2221 default:
2222 /* Prefix write. */
2223 stream_put_prefix (s, p);
2224 break;
2225 }
2226}
2227
2228void
2229bgp_packet_mpattr_end (struct stream *s, size_t sizep)
2230{
2231 /* Set MP attribute length. Don't count the (2) bytes used to encode
2232 the attr length */
2233 stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2);
2234}
2235
718e3744 2236/* Make attribute packet. */
2237bgp_size_t
2238bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
8c71e481 2239 struct stream *s, struct attr *attr,
3f9c7369 2240 struct bpacket_attr_vec_arr *vecarr,
8c71e481
PM
2241 struct prefix *p, afi_t afi, safi_t safi,
2242 struct peer *from, struct prefix_rd *prd, u_char *tag)
718e3744 2243{
fe69a505 2244 size_t cp;
0b2aa3a0 2245 size_t aspath_sizep;
718e3744 2246 struct aspath *aspath;
0b2aa3a0
PJ
2247 int send_as4_path = 0;
2248 int send_as4_aggregator = 0;
2249 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
8c71e481 2250 size_t mpattrlen_pos = 0;
718e3744 2251
2252 if (! bgp)
75aead62 2253 bgp = peer->bgp;
718e3744 2254
2255 /* Remember current pointer. */
9985f83c 2256 cp = stream_get_endp (s);
718e3744 2257
8c71e481
PM
2258 if (p && !(afi == AFI_IP && safi == SAFI_UNICAST))
2259 {
3f9c7369 2260 mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, vecarr, attr);
8c71e481
PM
2261 bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
2262 bgp_packet_mpattr_end(s, mpattrlen_pos);
2263 }
2264
718e3744 2265 /* Origin attribute. */
2266 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2267 stream_putc (s, BGP_ATTR_ORIGIN);
2268 stream_putc (s, 1);
2269 stream_putc (s, attr->origin);
2270
2271 /* AS path attribute. */
2272
2273 /* If remote-peer is EBGP */
6d85b15b 2274 if (peer->sort == BGP_PEER_EBGP
718e3744 2275 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
fe69a505 2276 || attr->aspath->segments == NULL)
fee0f4c6 2277 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
718e3744 2278 {
2279 aspath = aspath_dup (attr->aspath);
2280
2281 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2282 {
2283 /* Strip the confed info, and then stuff our path CONFED_ID
2284 on the front */
2285 aspath = aspath_delete_confed_seq (aspath);
2286 aspath = aspath_add_seq (aspath, bgp->confed_id);
2287 }
2288 else
2289 {
9d3f9705
AC
2290 if (peer->change_local_as) {
2291 /* If replace-as is specified, we only use the change_local_as when
2292 advertising routes. */
2293 if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
2294 aspath = aspath_add_seq (aspath, peer->local_as);
2295 }
718e3744 2296 aspath = aspath_add_seq (aspath, peer->change_local_as);
9d3f9705
AC
2297 } else {
2298 aspath = aspath_add_seq (aspath, peer->local_as);
2299 }
718e3744 2300 }
2301 }
6d85b15b 2302 else if (peer->sort == BGP_PEER_CONFED)
718e3744 2303 {
2304 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2305 aspath = aspath_dup (attr->aspath);
2306 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2307 }
2308 else
2309 aspath = attr->aspath;
2310
0b2aa3a0
PJ
2311 /* If peer is not AS4 capable, then:
2312 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2313 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2314 * types are in it (i.e. exclude them if they are there)
2315 * AND do this only if there is at least one asnum > 65535 in the path!
2316 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2317 * all ASnums > 65535 to BGP_AS_TRANS
2318 */
2319
2320 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2321 stream_putc (s, BGP_ATTR_AS_PATH);
2322 aspath_sizep = stream_get_endp (s);
2323 stream_putw (s, 0);
2324 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2325
2326 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2327 * in the path
2328 */
2329 if (!use32bit && aspath_has_as4 (aspath))
2330 send_as4_path = 1; /* we'll do this later, at the correct place */
2331
718e3744 2332 /* Nexthop attribute. */
2333 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2334 {
2335 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2336 stream_putc (s, BGP_ATTR_NEXT_HOP);
3f9c7369 2337 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
718e3744 2338 stream_putc (s, 4);
3f9c7369 2339 stream_put_ipv4 (s, attr->nexthop.s_addr);
718e3744 2340 }
2341
2342 /* MED attribute. */
abc920f8
DS
2343 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC) ||
2344 bgp->maxmed_active)
718e3744 2345 {
2346 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2347 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2348 stream_putc (s, 4);
abc920f8 2349 stream_putl (s, (bgp->maxmed_active ? bgp->maxmed_value : attr->med));
718e3744 2350 }
2351
2352 /* Local preference. */
6d85b15b
JBD
2353 if (peer->sort == BGP_PEER_IBGP ||
2354 peer->sort == BGP_PEER_CONFED)
718e3744 2355 {
2356 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2357 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2358 stream_putc (s, 4);
2359 stream_putl (s, attr->local_pref);
2360 }
2361
2362 /* Atomic aggregate. */
2363 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2364 {
2365 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2366 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2367 stream_putc (s, 0);
2368 }
2369
2370 /* Aggregator. */
2371 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2372 {
fb982c25 2373 assert (attr->extra);
0b2aa3a0
PJ
2374
2375 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
718e3744 2376 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2377 stream_putc (s, BGP_ATTR_AGGREGATOR);
0b2aa3a0
PJ
2378
2379 if (use32bit)
2380 {
2381 /* AS4 capable peer */
2382 stream_putc (s, 8);
2383 stream_putl (s, attr->extra->aggregator_as);
2384 }
2385 else
2386 {
2387 /* 2-byte AS peer */
2388 stream_putc (s, 6);
2389
2390 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2391 if ( attr->extra->aggregator_as > 65535 )
2392 {
2393 stream_putw (s, BGP_AS_TRANS);
2394
2395 /* we have to send AS4_AGGREGATOR, too.
2396 * we'll do that later in order to send attributes in ascending
2397 * order.
2398 */
2399 send_as4_aggregator = 1;
2400 }
2401 else
2402 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2403 }
fb982c25 2404 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
718e3744 2405 }
2406
2407 /* Community attribute. */
2408 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2409 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2410 {
2411 if (attr->community->size * 4 > 255)
2412 {
2413 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2414 stream_putc (s, BGP_ATTR_COMMUNITIES);
2415 stream_putw (s, attr->community->size * 4);
2416 }
2417 else
2418 {
2419 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2420 stream_putc (s, BGP_ATTR_COMMUNITIES);
2421 stream_putc (s, attr->community->size * 4);
2422 }
2423 stream_put (s, attr->community->val, attr->community->size * 4);
2424 }
2425
2426 /* Route Reflector. */
6d85b15b 2427 if (peer->sort == BGP_PEER_IBGP
718e3744 2428 && from
6d85b15b 2429 && from->sort == BGP_PEER_IBGP)
718e3744 2430 {
2431 /* Originator ID. */
2432 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2433 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2434 stream_putc (s, 4);
2435
2436 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
fb982c25 2437 stream_put_in_addr (s, &attr->extra->originator_id);
34c3f81b
PJ
2438 else
2439 stream_put_in_addr (s, &from->remote_id);
718e3744 2440
2441 /* Cluster list. */
2442 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2443 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2444
9eda90ce 2445 if (attr->extra && attr->extra->cluster)
718e3744 2446 {
fb982c25 2447 stream_putc (s, attr->extra->cluster->length + 4);
718e3744 2448 /* If this peer configuration's parent BGP has cluster_id. */
2449 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2450 stream_put_in_addr (s, &bgp->cluster_id);
2451 else
2452 stream_put_in_addr (s, &bgp->router_id);
fb982c25
PJ
2453 stream_put (s, attr->extra->cluster->list,
2454 attr->extra->cluster->length);
718e3744 2455 }
2456 else
2457 {
2458 stream_putc (s, 4);
2459 /* If this peer configuration's parent BGP has cluster_id. */
2460 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2461 stream_put_in_addr (s, &bgp->cluster_id);
2462 else
2463 stream_put_in_addr (s, &bgp->router_id);
2464 }
2465 }
2466
718e3744 2467 /* Extended Communities attribute. */
2468 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2469 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2470 {
fb982c25
PJ
2471 struct attr_extra *attre = attr->extra;
2472
2473 assert (attre);
2474
6d85b15b
JBD
2475 if (peer->sort == BGP_PEER_IBGP
2476 || peer->sort == BGP_PEER_CONFED)
718e3744 2477 {
fb982c25 2478 if (attre->ecommunity->size * 8 > 255)
4372df71 2479 {
2480 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2481 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
fb982c25 2482 stream_putw (s, attre->ecommunity->size * 8);
4372df71 2483 }
2484 else
2485 {
2486 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2487 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
fb982c25 2488 stream_putc (s, attre->ecommunity->size * 8);
4372df71 2489 }
fb982c25 2490 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
718e3744 2491 }
2492 else
2493 {
5228ad27 2494 u_int8_t *pnt;
4372df71 2495 int tbit;
2496 int ecom_tr_size = 0;
2497 int i;
2498
fb982c25 2499 for (i = 0; i < attre->ecommunity->size; i++)
4372df71 2500 {
fb982c25 2501 pnt = attre->ecommunity->val + (i * 8);
4372df71 2502 tbit = *pnt;
2503
2504 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2505 continue;
2506
2507 ecom_tr_size++;
2508 }
2509
2510 if (ecom_tr_size)
2511 {
2512 if (ecom_tr_size * 8 > 255)
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);
2516 stream_putw (s, ecom_tr_size * 8);
2517 }
2518 else
2519 {
2520 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2521 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2522 stream_putc (s, ecom_tr_size * 8);
2523 }
2524
fb982c25 2525 for (i = 0; i < attre->ecommunity->size; i++)
4372df71 2526 {
fb982c25 2527 pnt = attre->ecommunity->val + (i * 8);
4372df71 2528 tbit = *pnt;
2529
2530 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2531 continue;
2532
2533 stream_put (s, pnt, 8);
2534 }
2535 }
718e3744 2536 }
718e3744 2537 }
0b2aa3a0
PJ
2538
2539 if ( send_as4_path )
2540 {
2541 /* If the peer is NOT As4 capable, AND */
2542 /* there are ASnums > 65535 in path THEN
2543 * give out AS4_PATH */
2544
2545 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2546 * path segments!
2547 * Hm, I wonder... confederation things *should* only be at
2548 * the beginning of an aspath, right? Then we should use
2549 * aspath_delete_confed_seq for this, because it is already
2550 * there! (JK)
2551 * Folks, talk to me: what is reasonable here!?
2552 */
2553 aspath = aspath_delete_confed_seq (aspath);
2554
2555 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2556 stream_putc (s, BGP_ATTR_AS4_PATH);
2557 aspath_sizep = stream_get_endp (s);
2558 stream_putw (s, 0);
2559 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2560 }
2561
2562 if (aspath != attr->aspath)
2563 aspath_free (aspath);
2564
2565 if ( send_as4_aggregator )
2566 {
2567 assert (attr->extra);
2568
2569 /* send AS4_AGGREGATOR, at this place */
2570 /* this section of code moved here in order to ensure the correct
2571 * *ascending* order of attributes
2572 */
2573 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2574 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2575 stream_putc (s, 8);
2576 stream_putl (s, attr->extra->aggregator_as);
2577 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2578 }
41367172 2579
718e3744 2580 /* Unknown transit attribute. */
fb982c25
PJ
2581 if (attr->extra && attr->extra->transit)
2582 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
718e3744 2583
2584 /* Return total size of attribute. */
9985f83c 2585 return stream_get_endp (s) - cp;
718e3744 2586}
2587
8c71e481
PM
2588size_t
2589bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
718e3744 2590{
718e3744 2591 unsigned long attrlen_pnt;
718e3744 2592
8c71e481
PM
2593 /* Set extended bit always to encode the attribute length as 2 bytes */
2594 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
718e3744 2595 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2596
9985f83c 2597 attrlen_pnt = stream_get_endp (s);
8c71e481 2598 stream_putw (s, 0); /* Length of this attribute. */
718e3744 2599
8c71e481
PM
2600 stream_putw (s, afi);
2601 safi = (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi;
2602 stream_putc (s, safi);
2603 return attrlen_pnt;
2604}
718e3744 2605
8c71e481
PM
2606void
2607bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
2608 afi_t afi, safi_t safi, struct prefix_rd *prd,
2609 u_char *tag)
2610{
718e3744 2611 if (safi == SAFI_MPLS_VPN)
2612 {
718e3744 2613 stream_putc (s, p->prefixlen + 88);
2614 stream_put (s, tag, 3);
2615 stream_put (s, prd->val, 8);
2616 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2617 }
2618 else
8c71e481
PM
2619 stream_put_prefix (s, p);
2620}
718e3744 2621
8c71e481
PM
2622void
2623bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt)
2624{
2625 bgp_size_t size;
718e3744 2626
8c71e481
PM
2627 /* Set MP attribute length. Don't count the (2) bytes used to encode
2628 the attr length */
2629 size = stream_get_endp (s) - attrlen_pnt - 2;
2630 stream_putw_at (s, attrlen_pnt, size);
718e3744 2631}
2632
2633/* Initialization of attribute. */
2634void
fe69a505 2635bgp_attr_init (void)
718e3744 2636{
718e3744 2637 aspath_init ();
2638 attrhash_init ();
2639 community_init ();
2640 ecommunity_init ();
2641 cluster_init ();
2642 transit_init ();
2643}
2644
228da428
CC
2645void
2646bgp_attr_finish (void)
2647{
2648 aspath_finish ();
2649 attrhash_finish ();
2650 community_finish ();
2651 ecommunity_finish ();
2652 cluster_finish ();
2653 transit_finish ();
2654}
2655
718e3744 2656/* Make attribute packet. */
2657void
a384592f 2658bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2659 struct prefix *prefix)
718e3744 2660{
2661 unsigned long cp;
2662 unsigned long len;
0b2aa3a0 2663 size_t aspath_lenp;
718e3744 2664 struct aspath *aspath;
2665
2666 /* Remember current pointer. */
9985f83c 2667 cp = stream_get_endp (s);
718e3744 2668
2669 /* Place holder of length. */
2670 stream_putw (s, 0);
2671
2672 /* Origin attribute. */
2673 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2674 stream_putc (s, BGP_ATTR_ORIGIN);
2675 stream_putc (s, 1);
2676 stream_putc (s, attr->origin);
2677
2678 aspath = attr->aspath;
0b2aa3a0
PJ
2679
2680 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2681 stream_putc (s, BGP_ATTR_AS_PATH);
2682 aspath_lenp = stream_get_endp (s);
2683 stream_putw (s, 0);
2684
2685 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
718e3744 2686
2687 /* Nexthop attribute. */
a384592f 2688 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2689 if(prefix != NULL
2690#ifdef HAVE_IPV6
2691 && prefix->family != AF_INET6
2692#endif /* HAVE_IPV6 */
2693 )
2694 {
2695 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2696 stream_putc (s, BGP_ATTR_NEXT_HOP);
2697 stream_putc (s, 4);
2698 stream_put_ipv4 (s, attr->nexthop.s_addr);
2699 }
718e3744 2700
2701 /* MED attribute. */
2702 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2703 {
2704 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2705 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2706 stream_putc (s, 4);
2707 stream_putl (s, attr->med);
2708 }
2709
2710 /* Local preference. */
2711 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2712 {
2713 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2714 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2715 stream_putc (s, 4);
2716 stream_putl (s, attr->local_pref);
2717 }
2718
2719 /* Atomic aggregate. */
2720 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2721 {
2722 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2723 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2724 stream_putc (s, 0);
2725 }
2726
2727 /* Aggregator. */
2728 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2729 {
fb982c25 2730 assert (attr->extra);
718e3744 2731 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2732 stream_putc (s, BGP_ATTR_AGGREGATOR);
0b2aa3a0
PJ
2733 stream_putc (s, 8);
2734 stream_putl (s, attr->extra->aggregator_as);
fb982c25 2735 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
718e3744 2736 }
2737
2738 /* Community attribute. */
2739 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2740 {
2741 if (attr->community->size * 4 > 255)
2742 {
2743 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2744 stream_putc (s, BGP_ATTR_COMMUNITIES);
2745 stream_putw (s, attr->community->size * 4);
2746 }
2747 else
2748 {
2749 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2750 stream_putc (s, BGP_ATTR_COMMUNITIES);
2751 stream_putc (s, attr->community->size * 4);
2752 }
2753 stream_put (s, attr->community->val, attr->community->size * 4);
2754 }
2755
a384592f 2756#ifdef HAVE_IPV6
2757 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
fb982c25 2758 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
801a9bcc
DS
2759 (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
2760 attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) )
a384592f 2761 {
2762 int sizep;
fb982c25
PJ
2763 struct attr_extra *attre = attr->extra;
2764
a384592f 2765 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2766 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
9985f83c 2767 sizep = stream_get_endp (s);
a384592f 2768
2769 /* MP header */
fb982c25 2770 stream_putc (s, 0); /* Marker: Attribute length. */
a384592f 2771 stream_putw(s, AFI_IP6); /* AFI */
2772 stream_putc(s, SAFI_UNICAST); /* SAFI */
2773
2774 /* Next hop */
fb982c25 2775 stream_putc(s, attre->mp_nexthop_len);
801a9bcc
DS
2776 stream_put(s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
2777 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
2778 stream_put(s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN);
a384592f 2779
2780 /* SNPA */
2781 stream_putc(s, 0);
2782
2783 /* Prefix */
2784 stream_put_prefix(s, prefix);
2785
2786 /* Set MP attribute length. */
9985f83c 2787 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
a384592f 2788 }
2789#endif /* HAVE_IPV6 */
2790
718e3744 2791 /* Return total size of attribute. */
9985f83c 2792 len = stream_get_endp (s) - cp - 2;
718e3744 2793 stream_putw_at (s, cp, len);
2794}