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