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