blob: 989c22b134b8d30b9e925219bbede1dfca108a2a [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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
41/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070042static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
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" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000059 { 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" },
paul718e3742002-12-13 20:15:29 +000063};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070064static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
Stephen Hemminger9bddac42009-05-15 09:59:51 -070066static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000067
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 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. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
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
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 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
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
Chris Caputo228da422009-07-18 05:44:03 +0000151#if 0
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
Stephen Hemminger393deb92008-08-18 14:13:29 -0700157 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
Chris Caputo228da422009-07-18 05:44:03 +0000170#endif
paul718e3742002-12-13 20:15:29 +0000171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
246 struct transit *ret;
247
248 if (transit->refcnt)
249 transit->refcnt--;
250
251 if (transit->refcnt == 0)
252 {
253 ret = hash_release (transit_hash, transit);
254 transit_free (transit);
255 }
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000259transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma923de652007-04-29 18:25:17 +0000261 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000262 unsigned int key = 0;
263 int length;
264 caddr_t pnt;
265
266 length = transit->length;
267 pnt = (caddr_t) transit->val;
268
269 while (length)
270 key += pnt[--length];
271
272 return key;
273}
274
paul94f2b392005-06-28 12:44:16 +0000275static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100276transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000277{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100278 const struct transit * transit1 = p1;
279 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000280
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100281 return (transit1->length == transit2->length &&
282 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000283}
284
paul94f2b392005-06-28 12:44:16 +0000285static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800286transit_init (void)
paul718e3742002-12-13 20:15:29 +0000287{
288 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
289}
Chris Caputo228da422009-07-18 05:44:03 +0000290
291static void
292transit_finish (void)
293{
294 hash_free (transit_hash);
295 transit_hash = NULL;
296}
paul718e3742002-12-13 20:15:29 +0000297
298/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700299static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000300
Paul Jakmafb982c22007-05-04 20:15:47 +0000301static struct attr_extra *
302bgp_attr_extra_new (void)
303{
304 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
305}
306
307void
308bgp_attr_extra_free (struct attr *attr)
309{
310 if (attr->extra)
311 {
312 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
313 attr->extra = NULL;
314 }
315}
316
317struct attr_extra *
318bgp_attr_extra_get (struct attr *attr)
319{
320 if (!attr->extra)
321 attr->extra = bgp_attr_extra_new();
322 return attr->extra;
323}
324
325/* Shallow copy of an attribute
326 * Though, not so shallow that it doesn't copy the contents
327 * of the attr_extra pointed to by 'extra'
328 */
329void
330bgp_attr_dup (struct attr *new, struct attr *orig)
331{
332 *new = *orig;
333 if (orig->extra)
334 {
335 new->extra = bgp_attr_extra_new();
336 *new->extra = *orig->extra;
337 }
338}
339
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000340unsigned long int
341attr_count (void)
342{
343 return attrhash->count;
344}
345
346unsigned long int
347attr_unknown_count (void)
348{
349 return transit_hash->count;
350}
351
paul718e3742002-12-13 20:15:29 +0000352unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000353attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000354{
Paul Jakma923de652007-04-29 18:25:17 +0000355 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000356 unsigned int key = 0;
357
358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000362
363 if (attr->extra)
364 {
365 key += attr->extra->aggregator_as;
366 key += attr->extra->aggregator_addr.s_addr;
367 key += attr->extra->weight;
368 key += attr->extra->mp_nexthop_global_in.s_addr;
369 }
370
paul718e3742002-12-13 20:15:29 +0000371 if (attr->aspath)
372 key += aspath_key_make (attr->aspath);
373 if (attr->community)
374 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000375
376 if (attr->extra)
377 {
378 if (attr->extra->ecommunity)
379 key += ecommunity_hash_make (attr->extra->ecommunity);
380 if (attr->extra->cluster)
381 key += cluster_hash_key_make (attr->extra->cluster);
382 if (attr->extra->transit)
383 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000384
385#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 {
387 int i;
388
389 key += attr->extra->mp_nexthop_len;
390 for (i = 0; i < 16; i++)
391 key += attr->extra->mp_nexthop_global.s6_addr[i];
392 for (i = 0; i < 16; i++)
393 key += attr->extra->mp_nexthop_local.s6_addr[i];
394 }
paul718e3742002-12-13 20:15:29 +0000395#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000396 }
paul718e3742002-12-13 20:15:29 +0000397
398 return key;
399}
400
401int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100402attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000403{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100404 const struct attr * attr1 = p1;
405 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000406
paul718e3742002-12-13 20:15:29 +0000407 if (attr1->flag == attr2->flag
408 && attr1->origin == attr2->origin
409 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000410 && attr1->aspath == attr2->aspath
411 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000412 && attr1->med == attr2->med
Paul Jakmae70e5752011-07-05 00:41:59 +0400413 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000414 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100415 const struct attr_extra *ae1 = attr1->extra;
416 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000417
418 if (ae1 && ae2
419 && ae1->aggregator_as == ae2->aggregator_as
420 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
421 && ae1->weight == ae2->weight
422#ifdef HAVE_IPV6
423 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
424 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
425 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
426#endif /* HAVE_IPV6 */
427 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
428 && ae1->ecommunity == ae2->ecommunity
429 && ae1->cluster == ae2->cluster
430 && ae1->transit == ae2->transit)
431 return 1;
432 else if (ae1 || ae2)
433 return 0;
434 /* neither attribute has extra attributes, so they're same */
435 return 1;
436 }
paul718e3742002-12-13 20:15:29 +0000437 else
438 return 0;
439}
440
paul94f2b392005-06-28 12:44:16 +0000441static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100442attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000443{
444 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
445}
446
paul94f2b392005-06-28 12:44:16 +0000447static void
Chris Caputo228da422009-07-18 05:44:03 +0000448attrhash_finish (void)
449{
450 hash_free (attrhash);
451 attrhash = NULL;
452}
453
454static void
paul718e3742002-12-13 20:15:29 +0000455attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
456{
457 struct attr *attr = backet->data;
458
459 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
460 inet_ntoa (attr->nexthop), VTY_NEWLINE);
461}
462
463void
464attr_show_all (struct vty *vty)
465{
466 hash_iterate (attrhash,
467 (void (*)(struct hash_backet *, void *))
468 attr_show_all_iterator,
469 vty);
470}
471
paul94f2b392005-06-28 12:44:16 +0000472static void *
Paul Jakma923de652007-04-29 18:25:17 +0000473bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000474{
Paul Jakma923de652007-04-29 18:25:17 +0000475 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000476 struct attr *attr;
477
478 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
479 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000480 if (val->extra)
481 {
482 attr->extra = bgp_attr_extra_new ();
483 *attr->extra = *val->extra;
484 }
paul718e3742002-12-13 20:15:29 +0000485 attr->refcnt = 0;
486 return attr;
487}
488
489/* Internet argument attribute. */
490struct attr *
491bgp_attr_intern (struct attr *attr)
492{
493 struct attr *find;
494
495 /* Intern referenced strucutre. */
496 if (attr->aspath)
497 {
498 if (! attr->aspath->refcnt)
499 attr->aspath = aspath_intern (attr->aspath);
500 else
501 attr->aspath->refcnt++;
502 }
503 if (attr->community)
504 {
505 if (! attr->community->refcnt)
506 attr->community = community_intern (attr->community);
507 else
508 attr->community->refcnt++;
509 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000510 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000511 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000512 struct attr_extra *attre = attr->extra;
513
514 if (attre->ecommunity)
515 {
516 if (! attre->ecommunity->refcnt)
517 attre->ecommunity = ecommunity_intern (attre->ecommunity);
518 else
519 attre->ecommunity->refcnt++;
520 }
521 if (attre->cluster)
522 {
523 if (! attre->cluster->refcnt)
524 attre->cluster = cluster_intern (attre->cluster);
525 else
526 attre->cluster->refcnt++;
527 }
528 if (attre->transit)
529 {
530 if (! attre->transit->refcnt)
531 attre->transit = transit_intern (attre->transit);
532 else
533 attre->transit->refcnt++;
534 }
paul718e3742002-12-13 20:15:29 +0000535 }
536
537 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
538 find->refcnt++;
539
540 return find;
541}
542
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544/* Make network statement's attribute. */
545struct attr *
546bgp_attr_default_set (struct attr *attr, u_char origin)
547{
548 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000549 bgp_attr_extra_get (attr);
550
paul718e3742002-12-13 20:15:29 +0000551 attr->origin = origin;
552 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
553 attr->aspath = aspath_empty ();
554 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000556 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
557#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000559#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000560
paul718e3742002-12-13 20:15:29 +0000561 return attr;
562}
563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564
paul718e3742002-12-13 20:15:29 +0000565/* Make network statement's attribute. */
566struct attr *
567bgp_attr_default_intern (u_char origin)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
572
573 memset (&attr, 0, sizeof (struct attr));
574 attre = bgp_attr_extra_get (&attr);
575
Paul Jakma03e214c2007-04-29 18:31:07 +0000576 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000577
578 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 bgp_attr_extra_free (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 aspath_unintern (new->aspath);
582 return new;
583}
584
585struct attr *
586bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
587 struct aspath *aspath,
588 struct community *community, int as_set)
589{
590 struct attr attr;
591 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000592 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000593
594 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000595 attre = bgp_attr_extra_get (&attr);
596
paul718e3742002-12-13 20:15:29 +0000597 /* Origin attribute. */
598 attr.origin = origin;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
600
601 /* AS path attribute. */
602 if (aspath)
603 attr.aspath = aspath_intern (aspath);
604 else
605 attr.aspath = aspath_empty ();
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
607
608 /* Next hop attribute. */
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
610
611 if (community)
612 {
613 attr.community = community;
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
615 }
616
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000618#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000619 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000620#endif
621 if (! as_set)
622 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
623 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
624 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000625 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000626 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 attre->aggregator_as = bgp->as;
628 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000629
630 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000631 bgp_attr_extra_free (&attr);
632
paul718e3742002-12-13 20:15:29 +0000633 aspath_unintern (new->aspath);
634 return new;
635}
636
637/* Free bgp attribute and aspath. */
638void
639bgp_attr_unintern (struct attr *attr)
640{
641 struct attr *ret;
642 struct aspath *aspath;
643 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000644 struct ecommunity *ecommunity = NULL;
645 struct cluster_list *cluster = NULL;
646 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000647
648 /* Decrement attribute reference. */
649 attr->refcnt--;
650 aspath = attr->aspath;
651 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000652 if (attr->extra)
653 {
654 ecommunity = attr->extra->ecommunity;
655 cluster = attr->extra->cluster;
656 transit = attr->extra->transit;
657 }
paul718e3742002-12-13 20:15:29 +0000658
659 /* If reference becomes zero then free attribute object. */
660 if (attr->refcnt == 0)
661 {
662 ret = hash_release (attrhash, attr);
663 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000664 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000665 XFREE (MTYPE_ATTR, attr);
666 }
667
668 /* aspath refcount shoud be decrement. */
669 if (aspath)
670 aspath_unintern (aspath);
671 if (community)
672 community_unintern (community);
673 if (ecommunity)
674 ecommunity_unintern (ecommunity);
675 if (cluster)
676 cluster_unintern (cluster);
677 if (transit)
678 transit_unintern (transit);
679}
680
681void
682bgp_attr_flush (struct attr *attr)
683{
684 if (attr->aspath && ! attr->aspath->refcnt)
685 aspath_free (attr->aspath);
686 if (attr->community && ! attr->community->refcnt)
687 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000688 if (attr->extra)
689 {
690 struct attr_extra *attre = attr->extra;
691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
692 ecommunity_free (attre->ecommunity);
693 if (attre->cluster && ! attre->cluster->refcnt)
694 cluster_free (attre->cluster);
695 if (attre->transit && ! attre->transit->refcnt)
696 transit_free (attre->transit);
697 }
paul718e3742002-12-13 20:15:29 +0000698}
699
700/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000701static int
paul718e3742002-12-13 20:15:29 +0000702bgp_attr_origin (struct peer *peer, bgp_size_t length,
703 struct attr *attr, u_char flag, u_char *startp)
704{
705 bgp_size_t total;
706
707 /* total is entire attribute length include Attribute Flags (1),
708 Attribute Type code (1) and Attribute length (1 or 2). */
709 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
710
711 /* If any recognized attribute has Attribute Flags that conflict
712 with the Attribute Type Code, then the Error Subcode is set to
713 Attribute Flags Error. The Data field contains the erroneous
714 attribute (type, length and value). */
715 if (flag != BGP_ATTR_FLAG_TRANS)
716 {
717 zlog (peer->log, LOG_ERR,
718 "Origin attribute flag isn't transitive %d", flag);
719 bgp_notify_send_with_data (peer,
720 BGP_NOTIFY_UPDATE_ERR,
721 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
722 startp, total);
723 return -1;
724 }
725
726 /* If any recognized attribute has Attribute Length that conflicts
727 with the expected length (based on the attribute type code), then
728 the Error Subcode is set to Attribute Length Error. The Data
729 field contains the erroneous attribute (type, length and
730 value). */
731 if (length != 1)
732 {
733 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
734 length);
735 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
736 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
737 startp, total);
738 return -1;
739 }
740
741 /* Fetch origin attribute. */
742 attr->origin = stream_getc (BGP_INPUT (peer));
743
744 /* If the ORIGIN attribute has an undefined value, then the Error
745 Subcode is set to Invalid Origin Attribute. The Data field
746 contains the unrecognized attribute (type, length and value). */
747 if ((attr->origin != BGP_ORIGIN_IGP)
748 && (attr->origin != BGP_ORIGIN_EGP)
749 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
750 {
751 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
752 attr->origin);
753
754 bgp_notify_send_with_data (peer,
755 BGP_NOTIFY_UPDATE_ERR,
756 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
757 startp, total);
758 return -1;
759 }
760
761 /* Set oring attribute flag. */
762 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
763
764 return 0;
765}
Chris Hallcddb8112010-08-09 22:31:37 +0400766/* Parse AS path information. This function is wrapper of aspath_parse.
767 *
768 * Parses AS_PATH or AS4_PATH.
769 *
770 * Returns: if valid: address of struct aspath in the hash of known aspaths,
771 * with reference count incremented.
772 * else: NULL
773 *
774 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
775 * have segments == NULL and str == zero length string (unique).
776 */
777static struct aspath *
paul718e3742002-12-13 20:15:29 +0000778bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400779 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000780{
Chris Hallcddb8112010-08-09 22:31:37 +0400781 u_char require ;
782 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000783
Chris Hallcddb8112010-08-09 22:31:37 +0400784 /* Check the attribute flags */
785 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
786 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000787
Chris Hallcddb8112010-08-09 22:31:37 +0400788 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000789 {
Chris Hallcddb8112010-08-09 22:31:37 +0400790 const char* path_type ;
791 bgp_size_t total;
792
793 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
794
795 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000796 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400797 "%s attribute flag isn't transitive %d", path_type, flag) ;
798
799 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
800 zlog (peer->log, LOG_ERR,
801 "%s attribute flag must %sbe optional %d", path_type,
802 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
803
804 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
805
paul718e3742002-12-13 20:15:29 +0000806 bgp_notify_send_with_data (peer,
807 BGP_NOTIFY_UPDATE_ERR,
808 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
809 startp, total);
paul718e3742002-12-13 20:15:29 +0000810
Chris Hallcddb8112010-08-09 22:31:37 +0400811 return NULL ;
812 } ;
813
814 /* Parse the AS_PATH/AS4_PATH body.
815 *
816 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
817 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000818 */
Chris Hallcddb8112010-08-09 22:31:37 +0400819 asp = aspath_parse (peer->ibuf, length,
820 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000821
Chris Hallcddb8112010-08-09 22:31:37 +0400822 if (asp != NULL)
823 {
824 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
825 : BGP_ATTR_AS_PATH) ;
826 }
827 else
paul718e3742002-12-13 20:15:29 +0000828 {
829 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400830
831 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000832 bgp_notify_send (peer,
833 BGP_NOTIFY_UPDATE_ERR,
834 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400835 } ;
paul718e3742002-12-13 20:15:29 +0000836
Chris Hallcddb8112010-08-09 22:31:37 +0400837 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000838}
839
840static int bgp_attr_aspath_check( struct peer *peer,
841 struct attr *attr)
842{
843 /* These checks were part of bgp_attr_aspath, but with
844 * as4 we should to check aspath things when
845 * aspath synthesizing with as4_path has already taken place.
846 * Otherwise we check ASPATH and use the synthesized thing, and that is
847 * not right.
848 * So do the checks later, i.e. here
849 */
850 struct bgp *bgp = peer->bgp;
851 struct aspath *aspath;
852
paul718e3742002-12-13 20:15:29 +0000853 bgp = peer->bgp;
854
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300855 /* Confederation sanity check. */
856 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
857 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
858 {
859 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
860 bgp_notify_send (peer,
861 BGP_NOTIFY_UPDATE_ERR,
862 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
863 return -1;
864 }
865
paul718e3742002-12-13 20:15:29 +0000866 /* First AS check for EBGP. */
867 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
868 {
869 if (peer_sort (peer) == BGP_PEER_EBGP
870 && ! aspath_firstas_check (attr->aspath, peer->as))
871 {
872 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400873 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000874 bgp_notify_send (peer,
875 BGP_NOTIFY_UPDATE_ERR,
876 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
877 return -1;
878 }
879 }
880
881 /* local-as prepend */
882 if (peer->change_local_as &&
883 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
884 {
885 aspath = aspath_dup (attr->aspath);
886 aspath = aspath_add_seq (aspath, peer->change_local_as);
887 aspath_unintern (attr->aspath);
888 attr->aspath = aspath_intern (aspath);
889 }
890
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000891 return 0;
892
893}
894
paul718e3742002-12-13 20:15:29 +0000895/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000896static int
paul718e3742002-12-13 20:15:29 +0000897bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
898 struct attr *attr, u_char flag, u_char *startp)
899{
900 bgp_size_t total;
901
902 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
903
904 /* Flag check. */
905 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
906 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
907 {
908 zlog (peer->log, LOG_ERR,
909 "Origin attribute flag isn't transitive %d", flag);
910 bgp_notify_send_with_data (peer,
911 BGP_NOTIFY_UPDATE_ERR,
912 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
913 startp, total);
914 return -1;
915 }
916
917 /* Check nexthop attribute length. */
918 if (length != 4)
919 {
920 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
921 length);
922
923 bgp_notify_send_with_data (peer,
924 BGP_NOTIFY_UPDATE_ERR,
925 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
926 startp, total);
927 return -1;
928 }
929
930 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
931 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
932
933 return 0;
934}
935
936/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000937static int
paul718e3742002-12-13 20:15:29 +0000938bgp_attr_med (struct peer *peer, bgp_size_t length,
939 struct attr *attr, u_char flag, u_char *startp)
940{
941 bgp_size_t total;
942
943 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
944
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400945 /* Flag checks. */
946 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
947 {
948 zlog (peer->log, LOG_ERR,
949 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
950 bgp_notify_send_with_data (peer,
951 BGP_NOTIFY_UPDATE_ERR,
952 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
953 startp, total);
954 return -1;
955 }
956 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
957 {
958 zlog (peer->log, LOG_ERR,
959 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
960 bgp_notify_send_with_data (peer,
961 BGP_NOTIFY_UPDATE_ERR,
962 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
963 startp, total);
964 return -1;
965 }
966 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
967 {
968 zlog (peer->log, LOG_ERR,
969 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
970 bgp_notify_send_with_data (peer,
971 BGP_NOTIFY_UPDATE_ERR,
972 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
973 startp, total);
974 return -1;
975 }
976
paul718e3742002-12-13 20:15:29 +0000977 /* Length check. */
978 if (length != 4)
979 {
980 zlog (peer->log, LOG_ERR,
981 "MED attribute length isn't four [%d]", length);
982
983 bgp_notify_send_with_data (peer,
984 BGP_NOTIFY_UPDATE_ERR,
985 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
986 startp, total);
987 return -1;
988 }
989
990 attr->med = stream_getl (peer->ibuf);
991
992 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
993
994 return 0;
995}
996
997/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000998static int
paul718e3742002-12-13 20:15:29 +0000999bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001000 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001001{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001002 bgp_size_t total;
1003
1004 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1005 /* Flag checks. */
1006 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1007 {
1008 zlog (peer->log, LOG_ERR,
1009 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1010 bgp_notify_send_with_data (peer,
1011 BGP_NOTIFY_UPDATE_ERR,
1012 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1013 startp, total);
1014 return -1;
1015 }
1016 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1017 {
1018 zlog (peer->log, LOG_ERR,
1019 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1020 bgp_notify_send_with_data (peer,
1021 BGP_NOTIFY_UPDATE_ERR,
1022 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1023 startp, total);
1024 return -1;
1025 }
1026
paul718e3742002-12-13 20:15:29 +00001027 /* If it is contained in an UPDATE message that is received from an
1028 external peer, then this attribute MUST be ignored by the
1029 receiving speaker. */
1030 if (peer_sort (peer) == BGP_PEER_EBGP)
1031 {
paul9985f832005-02-09 15:51:56 +00001032 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001033 return 0;
1034 }
1035
1036 if (length == 4)
1037 attr->local_pref = stream_getl (peer->ibuf);
1038 else
1039 attr->local_pref = 0;
1040
1041 /* Set atomic aggregate flag. */
1042 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1043
1044 return 0;
1045}
1046
1047/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001048static int
paul718e3742002-12-13 20:15:29 +00001049bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001050 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001051{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001052 bgp_size_t total;
1053
1054 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1055 /* Flag checks. */
1056 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1057 {
1058 zlog (peer->log, LOG_ERR,
1059 "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1060 bgp_notify_send_with_data (peer,
1061 BGP_NOTIFY_UPDATE_ERR,
1062 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1063 startp, total);
1064 return -1;
1065 }
1066 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1067 {
1068 zlog (peer->log, LOG_ERR,
1069 "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1070 bgp_notify_send_with_data (peer,
1071 BGP_NOTIFY_UPDATE_ERR,
1072 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1073 startp, total);
1074 return -1;
1075 }
1076 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1077 {
1078 zlog (peer->log, LOG_ERR,
1079 "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1080 bgp_notify_send_with_data (peer,
1081 BGP_NOTIFY_UPDATE_ERR,
1082 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1083 startp, total);
1084 return -1;
1085 }
1086
1087 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001088 if (length != 0)
1089 {
1090 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1091
1092 bgp_notify_send (peer,
1093 BGP_NOTIFY_UPDATE_ERR,
1094 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1095 return -1;
1096 }
1097
1098 /* Set atomic aggregate flag. */
1099 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1100
1101 return 0;
1102}
1103
1104/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001105static int
paul718e3742002-12-13 20:15:29 +00001106bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1107 struct attr *attr, u_char flag)
1108{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001109 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001110 struct attr_extra *attre = bgp_attr_extra_get (attr);
1111
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001112 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1113 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1114 wantedlen = 8;
1115
1116 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001117 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001118 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001119
1120 bgp_notify_send (peer,
1121 BGP_NOTIFY_UPDATE_ERR,
1122 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1123 return -1;
1124 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001125
1126 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1127 attre->aggregator_as = stream_getl (peer->ibuf);
1128 else
1129 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001130 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001131
1132 /* Set atomic aggregate flag. */
1133 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1134
1135 return 0;
1136}
1137
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001138/* New Aggregator attribute */
1139static int
1140bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1141 struct attr *attr, as_t *as4_aggregator_as,
1142 struct in_addr *as4_aggregator_addr)
1143{
1144 if (length != 8)
1145 {
1146 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1147
1148 bgp_notify_send (peer,
1149 BGP_NOTIFY_UPDATE_ERR,
1150 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1151 return -1;
1152 }
1153 *as4_aggregator_as = stream_getl (peer->ibuf);
1154 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1155
1156 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1157
1158 return 0;
1159}
1160
1161/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1162 */
1163static int
1164bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1165 struct aspath *as4_path, as_t as4_aggregator,
1166 struct in_addr *as4_aggregator_addr)
1167{
1168 int ignore_as4_path = 0;
1169 struct aspath *newpath;
1170 struct attr_extra *attre = attr->extra;
1171
1172 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1173 {
1174 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1175 * if given.
1176 * It is worth a warning though, because the peer really
1177 * should not send them
1178 */
1179 if (BGP_DEBUG(as4, AS4))
1180 {
1181 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1182 zlog_debug ("[AS4] %s %s AS4_PATH",
1183 peer->host, "AS4 capable peer, yet it sent");
1184
1185 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1186 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1187 peer->host, "AS4 capable peer, yet it sent");
1188 }
1189
1190 return 0;
1191 }
1192
1193 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1194 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1195 {
1196 /* Hu? This is not supposed to happen at all!
1197 * got as4_path and no aspath,
1198 * This should already
1199 * have been handled by 'well known attributes missing'
1200 * But... yeah, paranoia
1201 * Take this as a "malformed attribute"
1202 */
1203 zlog (peer->log, LOG_ERR,
1204 "%s BGP not AS4 capable peer sent AS4_PATH but"
1205 " no AS_PATH, cant do anything here", peer->host);
1206 bgp_notify_send (peer,
1207 BGP_NOTIFY_UPDATE_ERR,
1208 BGP_NOTIFY_UPDATE_MAL_ATTR);
1209 return -1;
1210 }
1211
1212 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1213 * because that may override AS4_PATH
1214 */
1215 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1216 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001217 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1218 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001219 assert (attre);
1220
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001221 /* received both.
1222 * if the as_number in aggregator is not AS_TRANS,
1223 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1224 * and the Aggregator shall be taken as
1225 * info on the aggregating node, and the AS_PATH
1226 * shall be taken as the AS_PATH
1227 * otherwise
1228 * the Aggregator shall be ignored and the
1229 * AS4_AGGREGATOR shall be taken as the
1230 * Aggregating node and the AS_PATH is to be
1231 * constructed "as in all other cases"
1232 */
1233 if ( attre->aggregator_as != BGP_AS_TRANS )
1234 {
1235 /* ignore */
1236 if ( BGP_DEBUG(as4, AS4))
1237 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1238 " send AGGREGATOR != AS_TRANS and"
1239 " AS4_AGGREGATOR, so ignore"
1240 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1241 ignore_as4_path = 1;
1242 }
1243 else
1244 {
1245 /* "New_aggregator shall be taken as aggregator" */
1246 attre->aggregator_as = as4_aggregator;
1247 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1248 }
1249 }
1250 else
1251 {
1252 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1253 * That is bogus - but reading the conditions
1254 * we have to handle AS4_AGGREGATOR as if it were
1255 * AGGREGATOR in that case
1256 */
1257 if ( BGP_DEBUG(as4, AS4))
1258 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1259 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1260 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001261 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001262 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1263 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1264 }
1265 }
1266
1267 /* need to reconcile NEW_AS_PATH and AS_PATH */
1268 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1269 {
1270 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1271 aspath_unintern (attr->aspath);
1272 attr->aspath = aspath_intern (newpath);
1273 }
1274 return 0;
1275}
1276
paul718e3742002-12-13 20:15:29 +00001277/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001278static int
paul718e3742002-12-13 20:15:29 +00001279bgp_attr_community (struct peer *peer, bgp_size_t length,
1280 struct attr *attr, u_char flag)
1281{
1282 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001283 {
1284 attr->community = NULL;
1285 return 0;
1286 }
Paul Jakmafc097162010-12-05 17:17:26 +00001287
1288 attr->community =
1289 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1290
1291 /* XXX: fix community_parse to use stream API and remove this */
1292 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001293
Paul Jakmafc097162010-12-05 17:17:26 +00001294 if (!attr->community)
1295 return -1;
1296
paul718e3742002-12-13 20:15:29 +00001297 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1298
1299 return 0;
1300}
1301
1302/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001303static int
paul718e3742002-12-13 20:15:29 +00001304bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1305 struct attr *attr, u_char flag)
1306{
1307 if (length != 4)
1308 {
1309 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1310
1311 bgp_notify_send (peer,
1312 BGP_NOTIFY_UPDATE_ERR,
1313 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1314 return -1;
1315 }
1316
Paul Jakmafb982c22007-05-04 20:15:47 +00001317 (bgp_attr_extra_get (attr))->originator_id.s_addr
1318 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001319
1320 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1321
1322 return 0;
1323}
1324
1325/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001326static int
paul718e3742002-12-13 20:15:29 +00001327bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1328 struct attr *attr, u_char flag)
1329{
1330 /* Check length. */
1331 if (length % 4)
1332 {
1333 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1334
1335 bgp_notify_send (peer,
1336 BGP_NOTIFY_UPDATE_ERR,
1337 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1338 return -1;
1339 }
1340
Paul Jakmafb982c22007-05-04 20:15:47 +00001341 (bgp_attr_extra_get (attr))->cluster
1342 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001343
paul9985f832005-02-09 15:51:56 +00001344 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001345
1346 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1347
1348 return 0;
1349}
1350
1351/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001352int
paul718e3742002-12-13 20:15:29 +00001353bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1354 struct bgp_nlri *mp_update)
1355{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001356 afi_t afi;
1357 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001358 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001359 size_t start;
paul718e3742002-12-13 20:15:29 +00001360 int ret;
1361 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001362 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001363
1364 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001365 s = BGP_INPUT(peer);
1366 start = stream_get_getp(s);
1367
1368 /* safe to read statically sized header? */
1369#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001370#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001371 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001372 {
1373 zlog_info ("%s: %s sent invalid length, %lu",
1374 __func__, peer->host, (unsigned long)length);
1375 return -1;
1376 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001377
paul718e3742002-12-13 20:15:29 +00001378 /* Load AFI, SAFI. */
1379 afi = stream_getw (s);
1380 safi = stream_getc (s);
1381
1382 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001383 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001384
Paul Jakma03292802008-06-07 20:37:10 +00001385 if (LEN_LEFT < attre->mp_nexthop_len)
1386 {
1387 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1388 __func__, peer->host, attre->mp_nexthop_len);
1389 return -1;
1390 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001391
paul718e3742002-12-13 20:15:29 +00001392 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001393 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001394 {
1395 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001396 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001397 /* Probably needed for RFC 2283 */
1398 if (attr->nexthop.s_addr == 0)
1399 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001400 break;
1401 case 12:
1402 {
1403 u_int32_t rd_high;
1404 u_int32_t rd_low;
1405
1406 rd_high = stream_getl (s);
1407 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001408 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001409 }
1410 break;
1411#ifdef HAVE_IPV6
1412 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001413 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001414 break;
1415 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001416 stream_get (&attre->mp_nexthop_global, s, 16);
1417 stream_get (&attre->mp_nexthop_local, s, 16);
1418 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001419 {
1420 char buf1[INET6_ADDRSTRLEN];
1421 char buf2[INET6_ADDRSTRLEN];
1422
1423 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001424 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
Paul Jakmafb982c22007-05-04 20:15:47 +00001425 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001426 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001427 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001428 buf2, INET6_ADDRSTRLEN));
1429
Paul Jakmafb982c22007-05-04 20:15:47 +00001430 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001431 }
1432 break;
1433#endif /* HAVE_IPV6 */
1434 default:
Paul Jakma03292802008-06-07 20:37:10 +00001435 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1436 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001437 return -1;
paul718e3742002-12-13 20:15:29 +00001438 }
1439
Paul Jakma03292802008-06-07 20:37:10 +00001440 if (!LEN_LEFT)
1441 {
1442 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1443 __func__, peer->host);
1444 return -1;
1445 }
paul718e3742002-12-13 20:15:29 +00001446
Paul Jakma6e4ab122007-04-10 19:36:48 +00001447 {
1448 u_char val;
1449 if ((val = stream_getc (s)))
1450 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1451 peer->host, val);
1452 }
1453
1454 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001455 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001456 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001457 {
1458 zlog_info ("%s: (%s) Failed to read NLRI",
1459 __func__, peer->host);
1460 return -1;
1461 }
paul718e3742002-12-13 20:15:29 +00001462
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001463 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001464 {
1465 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001466 if (ret < 0)
1467 {
1468 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1469 __func__, peer->host);
1470 return -1;
1471 }
paul718e3742002-12-13 20:15:29 +00001472 }
1473
1474 mp_update->afi = afi;
1475 mp_update->safi = safi;
1476 mp_update->nlri = stream_pnt (s);
1477 mp_update->length = nlri_len;
1478
paul9985f832005-02-09 15:51:56 +00001479 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001480
1481 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001482#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001483}
1484
1485/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001486int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001487bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001488 struct bgp_nlri *mp_withdraw)
1489{
1490 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001491 afi_t afi;
1492 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001493 u_int16_t withdraw_len;
1494 int ret;
1495
1496 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001497
1498#define BGP_MP_UNREACH_MIN_SIZE 3
1499 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1500 return -1;
1501
paul718e3742002-12-13 20:15:29 +00001502 afi = stream_getw (s);
1503 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001504
1505 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001506
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001507 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001508 {
1509 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1510 if (ret < 0)
1511 return -1;
1512 }
1513
1514 mp_withdraw->afi = afi;
1515 mp_withdraw->safi = safi;
1516 mp_withdraw->nlri = stream_pnt (s);
1517 mp_withdraw->length = withdraw_len;
1518
paul9985f832005-02-09 15:51:56 +00001519 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001520
1521 return 0;
1522}
1523
1524/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001525static int
paul718e3742002-12-13 20:15:29 +00001526bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1527 struct attr *attr, u_char flag)
1528{
1529 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001530 {
1531 if (attr->extra)
1532 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001533 /* Empty extcomm doesn't seem to be invalid per se */
1534 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001535 }
Paul Jakmafc097162010-12-05 17:17:26 +00001536
1537 (bgp_attr_extra_get (attr))->ecommunity =
1538 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1539 /* XXX: fix ecommunity_parse to use stream API */
1540 stream_forward_getp (peer->ibuf, length);
1541
1542 if (!attr->extra->ecommunity)
1543 return -1;
1544
paul718e3742002-12-13 20:15:29 +00001545 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1546
1547 return 0;
1548}
1549
1550/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001551static int
paul718e3742002-12-13 20:15:29 +00001552bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1553 u_char type, bgp_size_t length, u_char *startp)
1554{
1555 bgp_size_t total;
1556 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001557 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001558
hassof4184462005-02-01 20:13:16 +00001559 if (BGP_DEBUG (normal, NORMAL))
1560 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1561 peer->host, type, length);
1562
paul718e3742002-12-13 20:15:29 +00001563 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001564 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001565 "Unknown attribute type %d length %d is received", type, length);
1566
1567 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001568 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001569
1570 /* Adjest total length to include type and length. */
1571 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1572
1573 /* If any of the mandatory well-known attributes are not recognized,
1574 then the Error Subcode is set to Unrecognized Well-known
1575 Attribute. The Data field contains the unrecognized attribute
1576 (type, length and value). */
1577 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1578 {
1579 /* Adjust startp to do not include flag value. */
1580 bgp_notify_send_with_data (peer,
1581 BGP_NOTIFY_UPDATE_ERR,
1582 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1583 startp, total);
1584 return -1;
1585 }
1586
1587 /* Unrecognized non-transitive optional attributes must be quietly
1588 ignored and not passed along to other BGP peers. */
1589 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1590 return 0;
1591
1592 /* If a path with recognized transitive optional attribute is
1593 accepted and passed along to other BGP peers and the Partial bit
1594 in the Attribute Flags octet is set to 1 by some previous AS, it
1595 is not set back to 0 by the current AS. */
1596 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1597
1598 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001599 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001600 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001601
Paul Jakmafb982c22007-05-04 20:15:47 +00001602 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001603
1604 if (transit->val)
1605 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1606 transit->length + total);
1607 else
1608 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1609
1610 memcpy (transit->val + transit->length, startp, total);
1611 transit->length += total;
1612
1613 return 0;
1614}
1615
1616/* Read attribute of update packet. This function is called from
1617 bgp_update() in bgpd.c. */
1618int
1619bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1620 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1621{
1622 int ret;
1623 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001624 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001625 bgp_size_t length;
1626 u_char *startp, *endp;
1627 u_char *attr_endp;
1628 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001629 /* we need the as4_path only until we have synthesized the as_path with it */
1630 /* same goes for as4_aggregator */
1631 struct aspath *as4_path = NULL;
1632 as_t as4_aggregator = 0;
1633 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001634
1635 /* Initialize bitmap. */
1636 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1637
1638 /* End pointer of BGP attribute. */
1639 endp = BGP_INPUT_PNT (peer) + size;
1640
1641 /* Get attributes to the end of attribute length. */
1642 while (BGP_INPUT_PNT (peer) < endp)
1643 {
1644 /* Check remaining length check.*/
1645 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1646 {
gdtc29fdba2004-12-09 14:46:46 +00001647 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001648 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001649 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001650 peer->host,
1651 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001652
1653 bgp_notify_send (peer,
1654 BGP_NOTIFY_UPDATE_ERR,
1655 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1656 return -1;
1657 }
1658
1659 /* Fetch attribute flag and type. */
1660 startp = BGP_INPUT_PNT (peer);
1661 flag = stream_getc (BGP_INPUT (peer));
1662 type = stream_getc (BGP_INPUT (peer));
1663
Paul Jakma370b64a2007-12-22 16:49:52 +00001664 /* Check whether Extended-Length applies and is in bounds */
1665 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1666 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1667 {
1668 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001669 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001670 peer->host,
1671 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1672
1673 bgp_notify_send (peer,
1674 BGP_NOTIFY_UPDATE_ERR,
1675 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1676 return -1;
1677 }
1678
paul718e3742002-12-13 20:15:29 +00001679 /* Check extended attribue length bit. */
1680 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1681 length = stream_getw (BGP_INPUT (peer));
1682 else
1683 length = stream_getc (BGP_INPUT (peer));
1684
1685 /* If any attribute appears more than once in the UPDATE
1686 message, then the Error Subcode is set to Malformed Attribute
1687 List. */
1688
1689 if (CHECK_BITMAP (seen, type))
1690 {
1691 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001692 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001693 peer->host, type);
1694
1695 bgp_notify_send (peer,
1696 BGP_NOTIFY_UPDATE_ERR,
1697 BGP_NOTIFY_UPDATE_MAL_ATTR);
1698 return -1;
1699 }
1700
1701 /* Set type to bitmap to check duplicate attribute. `type' is
1702 unsigned char so it never overflow bitmap range. */
1703
1704 SET_BITMAP (seen, type);
1705
1706 /* Overflow check. */
1707 attr_endp = BGP_INPUT_PNT (peer) + length;
1708
1709 if (attr_endp > endp)
1710 {
1711 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001712 "%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);
paul718e3742002-12-13 20:15:29 +00001713 bgp_notify_send (peer,
1714 BGP_NOTIFY_UPDATE_ERR,
1715 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1716 return -1;
1717 }
1718
1719 /* OK check attribute and store it's value. */
1720 switch (type)
1721 {
1722 case BGP_ATTR_ORIGIN:
1723 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1724 break;
1725 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001726 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1727 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001728 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001729 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001730 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1731 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001732 break;
paul718e3742002-12-13 20:15:29 +00001733 case BGP_ATTR_NEXT_HOP:
1734 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1735 break;
1736 case BGP_ATTR_MULTI_EXIT_DISC:
1737 ret = bgp_attr_med (peer, length, attr, flag, startp);
1738 break;
1739 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001740 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001741 break;
1742 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001743 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001744 break;
1745 case BGP_ATTR_AGGREGATOR:
1746 ret = bgp_attr_aggregator (peer, length, attr, flag);
1747 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001748 case BGP_ATTR_AS4_AGGREGATOR:
1749 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1750 break;
paul718e3742002-12-13 20:15:29 +00001751 case BGP_ATTR_COMMUNITIES:
1752 ret = bgp_attr_community (peer, length, attr, flag);
1753 break;
1754 case BGP_ATTR_ORIGINATOR_ID:
1755 ret = bgp_attr_originator_id (peer, length, attr, flag);
1756 break;
1757 case BGP_ATTR_CLUSTER_LIST:
1758 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1759 break;
1760 case BGP_ATTR_MP_REACH_NLRI:
1761 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1762 break;
1763 case BGP_ATTR_MP_UNREACH_NLRI:
1764 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1765 break;
1766 case BGP_ATTR_EXT_COMMUNITIES:
1767 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1768 break;
1769 default:
1770 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1771 break;
1772 }
1773
1774 /* If error occured immediately return to the caller. */
1775 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001776 {
1777 zlog (peer->log, LOG_WARNING,
1778 "%s: Attribute %s, parse error",
1779 peer->host,
1780 LOOKUP (attr_str, type));
1781 bgp_notify_send (peer,
1782 BGP_NOTIFY_UPDATE_ERR,
1783 BGP_NOTIFY_UPDATE_MAL_ATTR);
1784 return ret;
1785 }
paul718e3742002-12-13 20:15:29 +00001786
1787 /* Check the fetched length. */
1788 if (BGP_INPUT_PNT (peer) != attr_endp)
1789 {
1790 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001791 "%s: BGP attribute %s, fetch error",
1792 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001793 bgp_notify_send (peer,
1794 BGP_NOTIFY_UPDATE_ERR,
1795 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1796 return -1;
1797 }
1798 }
1799
1800 /* Check final read pointer is same as end pointer. */
1801 if (BGP_INPUT_PNT (peer) != endp)
1802 {
1803 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001804 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001805 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001806 bgp_notify_send (peer,
1807 BGP_NOTIFY_UPDATE_ERR,
1808 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1809 return -1;
1810 }
1811
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001812 /*
1813 * At this place we can see whether we got AS4_PATH and/or
1814 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1815 * We can not do this before we've read all attributes because
1816 * the as4 handling does not say whether AS4_PATH has to be sent
1817 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1818 * in relationship to AGGREGATOR.
1819 * So, to be defensive, we are not relying on any order and read
1820 * all attributes first, including these 32bit ones, and now,
1821 * afterwards, we look what and if something is to be done for as4.
1822 */
1823 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1824 as4_aggregator, &as4_aggregator_addr))
1825 return -1;
1826
1827 /* At this stage, we have done all fiddling with as4, and the
1828 * resulting info is in attr->aggregator resp. attr->aspath
1829 * so we can chuck as4_aggregator and as4_path alltogether in
1830 * order to save memory
1831 */
1832 if ( as4_path )
1833 {
1834 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1835 as4_path = NULL;
1836 /* The flag that we got this is still there, but that does not
1837 * do any trouble
1838 */
1839 }
1840 /*
1841 * The "rest" of the code does nothing with as4_aggregator.
1842 * there is no memory attached specifically which is not part
1843 * of the attr.
1844 * so ignoring just means do nothing.
1845 */
1846 /*
1847 * Finally do the checks on the aspath we did not do yet
1848 * because we waited for a potentially synthesized aspath.
1849 */
1850 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1851 {
1852 ret = bgp_attr_aspath_check( peer, attr );
1853 if ( ret < 0 )
1854 return ret;
1855 }
1856
paul718e3742002-12-13 20:15:29 +00001857 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001858 if (attr->extra && attr->extra->transit)
1859 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001860
1861 return 0;
1862}
1863
1864/* Well-known attribute check. */
1865int
1866bgp_attr_check (struct peer *peer, struct attr *attr)
1867{
1868 u_char type = 0;
1869
1870 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1871 type = BGP_ATTR_ORIGIN;
1872
1873 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1874 type = BGP_ATTR_AS_PATH;
1875
1876 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1877 type = BGP_ATTR_NEXT_HOP;
1878
1879 if (peer_sort (peer) == BGP_PEER_IBGP
1880 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1881 type = BGP_ATTR_LOCAL_PREF;
1882
1883 if (type)
1884 {
1885 zlog (peer->log, LOG_WARNING,
1886 "%s Missing well-known attribute %d.",
1887 peer->host, type);
1888 bgp_notify_send_with_data (peer,
1889 BGP_NOTIFY_UPDATE_ERR,
1890 BGP_NOTIFY_UPDATE_MISS_ATTR,
1891 &type, 1);
1892 return -1;
1893 }
1894 return 0;
1895}
1896
1897int stream_put_prefix (struct stream *, struct prefix *);
1898
1899/* Make attribute packet. */
1900bgp_size_t
1901bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1902 struct stream *s, struct attr *attr, struct prefix *p,
1903 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001904 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001905{
paulfe69a502005-09-10 16:55:02 +00001906 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001907 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001908 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001909 int send_as4_path = 0;
1910 int send_as4_aggregator = 0;
1911 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001912
1913 if (! bgp)
1914 bgp = bgp_get_default ();
1915
1916 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001917 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001918
1919 /* Origin attribute. */
1920 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1921 stream_putc (s, BGP_ATTR_ORIGIN);
1922 stream_putc (s, 1);
1923 stream_putc (s, attr->origin);
1924
1925 /* AS path attribute. */
1926
1927 /* If remote-peer is EBGP */
1928 if (peer_sort (peer) == BGP_PEER_EBGP
1929 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001930 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001931 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001932 {
1933 aspath = aspath_dup (attr->aspath);
1934
1935 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1936 {
1937 /* Strip the confed info, and then stuff our path CONFED_ID
1938 on the front */
1939 aspath = aspath_delete_confed_seq (aspath);
1940 aspath = aspath_add_seq (aspath, bgp->confed_id);
1941 }
1942 else
1943 {
1944 aspath = aspath_add_seq (aspath, peer->local_as);
1945 if (peer->change_local_as)
1946 aspath = aspath_add_seq (aspath, peer->change_local_as);
1947 }
1948 }
1949 else if (peer_sort (peer) == BGP_PEER_CONFED)
1950 {
1951 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1952 aspath = aspath_dup (attr->aspath);
1953 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1954 }
1955 else
1956 aspath = attr->aspath;
1957
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001958 /* If peer is not AS4 capable, then:
1959 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1960 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1961 * types are in it (i.e. exclude them if they are there)
1962 * AND do this only if there is at least one asnum > 65535 in the path!
1963 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1964 * all ASnums > 65535 to BGP_AS_TRANS
1965 */
paul718e3742002-12-13 20:15:29 +00001966
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001967 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1968 stream_putc (s, BGP_ATTR_AS_PATH);
1969 aspath_sizep = stream_get_endp (s);
1970 stream_putw (s, 0);
1971 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1972
1973 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1974 * in the path
1975 */
1976 if (!use32bit && aspath_has_as4 (aspath))
1977 send_as4_path = 1; /* we'll do this later, at the correct place */
1978
paul718e3742002-12-13 20:15:29 +00001979 /* Nexthop attribute. */
1980 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1981 {
1982 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1983 stream_putc (s, BGP_ATTR_NEXT_HOP);
1984 stream_putc (s, 4);
1985 if (safi == SAFI_MPLS_VPN)
1986 {
1987 if (attr->nexthop.s_addr == 0)
1988 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1989 else
1990 stream_put_ipv4 (s, attr->nexthop.s_addr);
1991 }
1992 else
1993 stream_put_ipv4 (s, attr->nexthop.s_addr);
1994 }
1995
1996 /* MED attribute. */
1997 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1998 {
1999 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2000 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2001 stream_putc (s, 4);
2002 stream_putl (s, attr->med);
2003 }
2004
2005 /* Local preference. */
2006 if (peer_sort (peer) == BGP_PEER_IBGP ||
2007 peer_sort (peer) == BGP_PEER_CONFED)
2008 {
2009 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2010 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2011 stream_putc (s, 4);
2012 stream_putl (s, attr->local_pref);
2013 }
2014
2015 /* Atomic aggregate. */
2016 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2017 {
2018 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2019 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2020 stream_putc (s, 0);
2021 }
2022
2023 /* Aggregator. */
2024 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2025 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002026 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002027
2028 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002029 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2030 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002031
2032 if (use32bit)
2033 {
2034 /* AS4 capable peer */
2035 stream_putc (s, 8);
2036 stream_putl (s, attr->extra->aggregator_as);
2037 }
2038 else
2039 {
2040 /* 2-byte AS peer */
2041 stream_putc (s, 6);
2042
2043 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2044 if ( attr->extra->aggregator_as > 65535 )
2045 {
2046 stream_putw (s, BGP_AS_TRANS);
2047
2048 /* we have to send AS4_AGGREGATOR, too.
2049 * we'll do that later in order to send attributes in ascending
2050 * order.
2051 */
2052 send_as4_aggregator = 1;
2053 }
2054 else
2055 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2056 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002057 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002058 }
2059
2060 /* Community attribute. */
2061 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2062 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2063 {
2064 if (attr->community->size * 4 > 255)
2065 {
2066 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2067 stream_putc (s, BGP_ATTR_COMMUNITIES);
2068 stream_putw (s, attr->community->size * 4);
2069 }
2070 else
2071 {
2072 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2073 stream_putc (s, BGP_ATTR_COMMUNITIES);
2074 stream_putc (s, attr->community->size * 4);
2075 }
2076 stream_put (s, attr->community->val, attr->community->size * 4);
2077 }
2078
2079 /* Route Reflector. */
2080 if (peer_sort (peer) == BGP_PEER_IBGP
2081 && from
2082 && peer_sort (from) == BGP_PEER_IBGP)
2083 {
2084 /* Originator ID. */
2085 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2086 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2087 stream_putc (s, 4);
2088
2089 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002090 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002091 else
2092 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002093
2094 /* Cluster list. */
2095 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2096 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2097
Paul Jakma9eda90c2007-08-30 13:36:17 +00002098 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002099 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002100 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002101 /* If this peer configuration's parent BGP has cluster_id. */
2102 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2103 stream_put_in_addr (s, &bgp->cluster_id);
2104 else
2105 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002106 stream_put (s, attr->extra->cluster->list,
2107 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002108 }
2109 else
2110 {
2111 stream_putc (s, 4);
2112 /* If this peer configuration's parent BGP has cluster_id. */
2113 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2114 stream_put_in_addr (s, &bgp->cluster_id);
2115 else
2116 stream_put_in_addr (s, &bgp->router_id);
2117 }
2118 }
2119
2120#ifdef HAVE_IPV6
2121 /* If p is IPv6 address put it into attribute. */
2122 if (p->family == AF_INET6)
2123 {
2124 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002125 struct attr_extra *attre = attr->extra;
2126
2127 assert (attr->extra);
2128
paul718e3742002-12-13 20:15:29 +00002129 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2130 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002131 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002132 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002133 stream_putw (s, AFI_IP6); /* AFI */
2134 stream_putc (s, safi); /* SAFI */
2135
Paul Jakmafb982c22007-05-04 20:15:47 +00002136 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002137
Paul Jakmafb982c22007-05-04 20:15:47 +00002138 if (attre->mp_nexthop_len == 16)
2139 stream_put (s, &attre->mp_nexthop_global, 16);
2140 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002141 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002142 stream_put (s, &attre->mp_nexthop_global, 16);
2143 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002144 }
2145
2146 /* SNPA */
2147 stream_putc (s, 0);
2148
paul718e3742002-12-13 20:15:29 +00002149 /* Prefix write. */
2150 stream_put_prefix (s, p);
2151
2152 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002153 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002154 }
2155#endif /* HAVE_IPV6 */
2156
2157 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2158 {
2159 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002160
2161 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2162 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002163 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002164 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002165 stream_putw (s, AFI_IP); /* AFI */
2166 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2167
2168 stream_putc (s, 4);
2169 stream_put_ipv4 (s, attr->nexthop.s_addr);
2170
2171 /* SNPA */
2172 stream_putc (s, 0);
2173
paul718e3742002-12-13 20:15:29 +00002174 /* Prefix write. */
2175 stream_put_prefix (s, p);
2176
2177 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002178 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002179 }
2180
2181 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2182 {
2183 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002184
2185 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2186 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002187 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002188 stream_putc (s, 0); /* Length of this attribute. */
2189 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002190 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002191
2192 stream_putc (s, 12);
2193 stream_putl (s, 0);
2194 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002195 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002196
2197 /* SNPA */
2198 stream_putc (s, 0);
2199
paul718e3742002-12-13 20:15:29 +00002200 /* Tag, RD, Prefix write. */
2201 stream_putc (s, p->prefixlen + 88);
2202 stream_put (s, tag, 3);
2203 stream_put (s, prd->val, 8);
2204 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2205
2206 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002207 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002208 }
2209
2210 /* Extended Communities attribute. */
2211 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2212 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2213 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002214 struct attr_extra *attre = attr->extra;
2215
2216 assert (attre);
2217
2218 if (peer_sort (peer) == BGP_PEER_IBGP
2219 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002220 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002221 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002222 {
2223 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2224 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002225 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002226 }
2227 else
2228 {
2229 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2230 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002231 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002232 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002233 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002234 }
2235 else
2236 {
paul5228ad22004-06-04 17:58:18 +00002237 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002238 int tbit;
2239 int ecom_tr_size = 0;
2240 int i;
2241
Paul Jakmafb982c22007-05-04 20:15:47 +00002242 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002243 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002244 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002245 tbit = *pnt;
2246
2247 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2248 continue;
2249
2250 ecom_tr_size++;
2251 }
2252
2253 if (ecom_tr_size)
2254 {
2255 if (ecom_tr_size * 8 > 255)
2256 {
2257 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2258 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2259 stream_putw (s, ecom_tr_size * 8);
2260 }
2261 else
2262 {
2263 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2264 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2265 stream_putc (s, ecom_tr_size * 8);
2266 }
2267
Paul Jakmafb982c22007-05-04 20:15:47 +00002268 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002269 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002270 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002271 tbit = *pnt;
2272
2273 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2274 continue;
2275
2276 stream_put (s, pnt, 8);
2277 }
2278 }
paul718e3742002-12-13 20:15:29 +00002279 }
paul718e3742002-12-13 20:15:29 +00002280 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002281
2282 if ( send_as4_path )
2283 {
2284 /* If the peer is NOT As4 capable, AND */
2285 /* there are ASnums > 65535 in path THEN
2286 * give out AS4_PATH */
2287
2288 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2289 * path segments!
2290 * Hm, I wonder... confederation things *should* only be at
2291 * the beginning of an aspath, right? Then we should use
2292 * aspath_delete_confed_seq for this, because it is already
2293 * there! (JK)
2294 * Folks, talk to me: what is reasonable here!?
2295 */
2296 aspath = aspath_delete_confed_seq (aspath);
2297
2298 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2299 stream_putc (s, BGP_ATTR_AS4_PATH);
2300 aspath_sizep = stream_get_endp (s);
2301 stream_putw (s, 0);
2302 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2303 }
2304
2305 if (aspath != attr->aspath)
2306 aspath_free (aspath);
2307
2308 if ( send_as4_aggregator )
2309 {
2310 assert (attr->extra);
2311
2312 /* send AS4_AGGREGATOR, at this place */
2313 /* this section of code moved here in order to ensure the correct
2314 * *ascending* order of attributes
2315 */
2316 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2317 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2318 stream_putc (s, 8);
2319 stream_putl (s, attr->extra->aggregator_as);
2320 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2321 }
Paul Jakma41367172007-08-06 15:24:51 +00002322
paul718e3742002-12-13 20:15:29 +00002323 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002324 if (attr->extra && attr->extra->transit)
2325 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002326
2327 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002328 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002329}
2330
2331bgp_size_t
2332bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2333 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002334 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002335{
2336 unsigned long cp;
2337 unsigned long attrlen_pnt;
2338 bgp_size_t size;
2339
paul9985f832005-02-09 15:51:56 +00002340 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002341
2342 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2343 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2344
paul9985f832005-02-09 15:51:56 +00002345 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002346 stream_putc (s, 0); /* Length of this attribute. */
2347
2348 stream_putw (s, family2afi (p->family));
2349
2350 if (safi == SAFI_MPLS_VPN)
2351 {
2352 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002353 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002354
2355 /* prefix. */
2356 stream_putc (s, p->prefixlen + 88);
2357 stream_put (s, tag, 3);
2358 stream_put (s, prd->val, 8);
2359 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2360 }
2361 else
2362 {
2363 /* SAFI */
2364 stream_putc (s, safi);
2365
2366 /* prefix */
2367 stream_put_prefix (s, p);
2368 }
2369
2370 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002371 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002372 stream_putc_at (s, attrlen_pnt, size);
2373
paul9985f832005-02-09 15:51:56 +00002374 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002375}
2376
2377/* Initialization of attribute. */
2378void
paulfe69a502005-09-10 16:55:02 +00002379bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002380{
paul718e3742002-12-13 20:15:29 +00002381 aspath_init ();
2382 attrhash_init ();
2383 community_init ();
2384 ecommunity_init ();
2385 cluster_init ();
2386 transit_init ();
2387}
2388
Chris Caputo228da422009-07-18 05:44:03 +00002389void
2390bgp_attr_finish (void)
2391{
2392 aspath_finish ();
2393 attrhash_finish ();
2394 community_finish ();
2395 ecommunity_finish ();
2396 cluster_finish ();
2397 transit_finish ();
2398}
2399
paul718e3742002-12-13 20:15:29 +00002400/* Make attribute packet. */
2401void
paula3845922003-10-18 01:30:50 +00002402bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2403 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002404{
2405 unsigned long cp;
2406 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002407 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002408 struct aspath *aspath;
2409
2410 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002411 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002412
2413 /* Place holder of length. */
2414 stream_putw (s, 0);
2415
2416 /* Origin attribute. */
2417 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2418 stream_putc (s, BGP_ATTR_ORIGIN);
2419 stream_putc (s, 1);
2420 stream_putc (s, attr->origin);
2421
2422 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002423
2424 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2425 stream_putc (s, BGP_ATTR_AS_PATH);
2426 aspath_lenp = stream_get_endp (s);
2427 stream_putw (s, 0);
2428
2429 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002430
2431 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002432 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2433 if(prefix != NULL
2434#ifdef HAVE_IPV6
2435 && prefix->family != AF_INET6
2436#endif /* HAVE_IPV6 */
2437 )
2438 {
2439 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2440 stream_putc (s, BGP_ATTR_NEXT_HOP);
2441 stream_putc (s, 4);
2442 stream_put_ipv4 (s, attr->nexthop.s_addr);
2443 }
paul718e3742002-12-13 20:15:29 +00002444
2445 /* MED attribute. */
2446 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2447 {
2448 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2449 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2450 stream_putc (s, 4);
2451 stream_putl (s, attr->med);
2452 }
2453
2454 /* Local preference. */
2455 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2456 {
2457 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2458 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2459 stream_putc (s, 4);
2460 stream_putl (s, attr->local_pref);
2461 }
2462
2463 /* Atomic aggregate. */
2464 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2465 {
2466 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2467 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2468 stream_putc (s, 0);
2469 }
2470
2471 /* Aggregator. */
2472 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2473 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002474 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002475 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2476 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002477 stream_putc (s, 8);
2478 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002479 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002480 }
2481
2482 /* Community attribute. */
2483 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2484 {
2485 if (attr->community->size * 4 > 255)
2486 {
2487 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2488 stream_putc (s, BGP_ATTR_COMMUNITIES);
2489 stream_putw (s, attr->community->size * 4);
2490 }
2491 else
2492 {
2493 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2494 stream_putc (s, BGP_ATTR_COMMUNITIES);
2495 stream_putc (s, attr->community->size * 4);
2496 }
2497 stream_put (s, attr->community->val, attr->community->size * 4);
2498 }
2499
paula3845922003-10-18 01:30:50 +00002500#ifdef HAVE_IPV6
2501 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002502 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2503 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002504 {
2505 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002506 struct attr_extra *attre = attr->extra;
2507
paula3845922003-10-18 01:30:50 +00002508 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2509 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002510 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002511
2512 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002513 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002514 stream_putw(s, AFI_IP6); /* AFI */
2515 stream_putc(s, SAFI_UNICAST); /* SAFI */
2516
2517 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002518 stream_putc(s, attre->mp_nexthop_len);
2519 stream_put(s, &attre->mp_nexthop_global, 16);
2520 if (attre->mp_nexthop_len == 32)
2521 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002522
2523 /* SNPA */
2524 stream_putc(s, 0);
2525
2526 /* Prefix */
2527 stream_put_prefix(s, prefix);
2528
2529 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002530 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002531 }
2532#endif /* HAVE_IPV6 */
2533
paul718e3742002-12-13 20:15:29 +00002534 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002535 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002536 stream_putw_at (s, cp, len);
2537}