blob: 251f15680b98fbd61d6c115dc96b1d0d6e2efc1e [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;
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400901 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000902
903 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
904
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400905 /* Flags check. */
906 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +0000907 {
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400908 zlog (peer->log, LOG_ERR,
909 "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", 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 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
917 {
918 zlog (peer->log, LOG_ERR,
919 "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
920 bgp_notify_send_with_data (peer,
921 BGP_NOTIFY_UPDATE_ERR,
922 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
923 startp, total);
924 return -1;
925 }
926 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
927 {
928 zlog (peer->log, LOG_ERR,
929 "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
930 bgp_notify_send_with_data (peer,
931 BGP_NOTIFY_UPDATE_ERR,
paul718e3742002-12-13 20:15:29 +0000932 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
933 startp, total);
934 return -1;
935 }
936
937 /* Check nexthop attribute length. */
938 if (length != 4)
939 {
940 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
941 length);
942
943 bgp_notify_send_with_data (peer,
944 BGP_NOTIFY_UPDATE_ERR,
945 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
946 startp, total);
947 return -1;
948 }
949
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400950 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
951 attribute must result in a NOTIFICATION message (this is implemented below).
952 At the same time, semantically incorrect NEXT_HOP is more likely to be just
953 logged locally (this is implemented somewhere else). The UPDATE message
954 gets ignored in any of these cases. */
955 nexthop_n = stream_get_ipv4 (peer->ibuf);
956 nexthop_h = ntohl (nexthop_n);
957 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
958 {
959 char buf[INET_ADDRSTRLEN];
960 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
961 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
962 bgp_notify_send_with_data (peer,
963 BGP_NOTIFY_UPDATE_ERR,
964 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
965 startp, total);
966 return -1;
967 }
968
969 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +0000970 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
971
972 return 0;
973}
974
975/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000976static int
paul718e3742002-12-13 20:15:29 +0000977bgp_attr_med (struct peer *peer, bgp_size_t length,
978 struct attr *attr, u_char flag, u_char *startp)
979{
980 bgp_size_t total;
981
982 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
983
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400984 /* Flag checks. */
985 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
986 {
987 zlog (peer->log, LOG_ERR,
988 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
989 bgp_notify_send_with_data (peer,
990 BGP_NOTIFY_UPDATE_ERR,
991 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
992 startp, total);
993 return -1;
994 }
995 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
996 {
997 zlog (peer->log, LOG_ERR,
998 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
999 bgp_notify_send_with_data (peer,
1000 BGP_NOTIFY_UPDATE_ERR,
1001 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1002 startp, total);
1003 return -1;
1004 }
1005 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1006 {
1007 zlog (peer->log, LOG_ERR,
1008 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
1009 bgp_notify_send_with_data (peer,
1010 BGP_NOTIFY_UPDATE_ERR,
1011 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1012 startp, total);
1013 return -1;
1014 }
1015
paul718e3742002-12-13 20:15:29 +00001016 /* Length check. */
1017 if (length != 4)
1018 {
1019 zlog (peer->log, LOG_ERR,
1020 "MED attribute length isn't four [%d]", length);
1021
1022 bgp_notify_send_with_data (peer,
1023 BGP_NOTIFY_UPDATE_ERR,
1024 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1025 startp, total);
1026 return -1;
1027 }
1028
1029 attr->med = stream_getl (peer->ibuf);
1030
1031 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1032
1033 return 0;
1034}
1035
1036/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001037static int
paul718e3742002-12-13 20:15:29 +00001038bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001039 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001040{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001041 bgp_size_t total;
1042
1043 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1044 /* Flag checks. */
1045 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1046 {
1047 zlog (peer->log, LOG_ERR,
1048 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1049 bgp_notify_send_with_data (peer,
1050 BGP_NOTIFY_UPDATE_ERR,
1051 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1052 startp, total);
1053 return -1;
1054 }
1055 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1056 {
1057 zlog (peer->log, LOG_ERR,
1058 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1059 bgp_notify_send_with_data (peer,
1060 BGP_NOTIFY_UPDATE_ERR,
1061 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1062 startp, total);
1063 return -1;
1064 }
1065
paul718e3742002-12-13 20:15:29 +00001066 /* If it is contained in an UPDATE message that is received from an
1067 external peer, then this attribute MUST be ignored by the
1068 receiving speaker. */
1069 if (peer_sort (peer) == BGP_PEER_EBGP)
1070 {
paul9985f832005-02-09 15:51:56 +00001071 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001072 return 0;
1073 }
1074
1075 if (length == 4)
1076 attr->local_pref = stream_getl (peer->ibuf);
1077 else
1078 attr->local_pref = 0;
1079
1080 /* Set atomic aggregate flag. */
1081 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1082
1083 return 0;
1084}
1085
1086/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001087static int
paul718e3742002-12-13 20:15:29 +00001088bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001089 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001090{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001091 bgp_size_t total;
1092
1093 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1094 /* Flag checks. */
1095 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1096 {
1097 zlog (peer->log, LOG_ERR,
1098 "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1099 bgp_notify_send_with_data (peer,
1100 BGP_NOTIFY_UPDATE_ERR,
1101 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1102 startp, total);
1103 return -1;
1104 }
1105 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1106 {
1107 zlog (peer->log, LOG_ERR,
1108 "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1109 bgp_notify_send_with_data (peer,
1110 BGP_NOTIFY_UPDATE_ERR,
1111 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1112 startp, total);
1113 return -1;
1114 }
1115 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1116 {
1117 zlog (peer->log, LOG_ERR,
1118 "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1119 bgp_notify_send_with_data (peer,
1120 BGP_NOTIFY_UPDATE_ERR,
1121 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1122 startp, total);
1123 return -1;
1124 }
1125
1126 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001127 if (length != 0)
1128 {
1129 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1130
1131 bgp_notify_send (peer,
1132 BGP_NOTIFY_UPDATE_ERR,
1133 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1134 return -1;
1135 }
1136
1137 /* Set atomic aggregate flag. */
1138 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1139
1140 return 0;
1141}
1142
1143/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001144static int
paul718e3742002-12-13 20:15:29 +00001145bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1146 struct attr *attr, u_char flag)
1147{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001148 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001149 struct attr_extra *attre = bgp_attr_extra_get (attr);
1150
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001151 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1152 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1153 wantedlen = 8;
1154
1155 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001156 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001157 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001158
1159 bgp_notify_send (peer,
1160 BGP_NOTIFY_UPDATE_ERR,
1161 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1162 return -1;
1163 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001164
1165 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1166 attre->aggregator_as = stream_getl (peer->ibuf);
1167 else
1168 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001169 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001170
1171 /* Set atomic aggregate flag. */
1172 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1173
1174 return 0;
1175}
1176
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001177/* New Aggregator attribute */
1178static int
1179bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1180 struct attr *attr, as_t *as4_aggregator_as,
1181 struct in_addr *as4_aggregator_addr)
1182{
1183 if (length != 8)
1184 {
1185 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1186
1187 bgp_notify_send (peer,
1188 BGP_NOTIFY_UPDATE_ERR,
1189 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1190 return -1;
1191 }
1192 *as4_aggregator_as = stream_getl (peer->ibuf);
1193 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1194
1195 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1196
1197 return 0;
1198}
1199
1200/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1201 */
1202static int
1203bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1204 struct aspath *as4_path, as_t as4_aggregator,
1205 struct in_addr *as4_aggregator_addr)
1206{
1207 int ignore_as4_path = 0;
1208 struct aspath *newpath;
1209 struct attr_extra *attre = attr->extra;
1210
1211 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1212 {
1213 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1214 * if given.
1215 * It is worth a warning though, because the peer really
1216 * should not send them
1217 */
1218 if (BGP_DEBUG(as4, AS4))
1219 {
1220 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1221 zlog_debug ("[AS4] %s %s AS4_PATH",
1222 peer->host, "AS4 capable peer, yet it sent");
1223
1224 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1225 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1226 peer->host, "AS4 capable peer, yet it sent");
1227 }
1228
1229 return 0;
1230 }
1231
1232 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1233 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1234 {
1235 /* Hu? This is not supposed to happen at all!
1236 * got as4_path and no aspath,
1237 * This should already
1238 * have been handled by 'well known attributes missing'
1239 * But... yeah, paranoia
1240 * Take this as a "malformed attribute"
1241 */
1242 zlog (peer->log, LOG_ERR,
1243 "%s BGP not AS4 capable peer sent AS4_PATH but"
1244 " no AS_PATH, cant do anything here", peer->host);
1245 bgp_notify_send (peer,
1246 BGP_NOTIFY_UPDATE_ERR,
1247 BGP_NOTIFY_UPDATE_MAL_ATTR);
1248 return -1;
1249 }
1250
1251 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1252 * because that may override AS4_PATH
1253 */
1254 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1255 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001256 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1257 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001258 assert (attre);
1259
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001260 /* received both.
1261 * if the as_number in aggregator is not AS_TRANS,
1262 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1263 * and the Aggregator shall be taken as
1264 * info on the aggregating node, and the AS_PATH
1265 * shall be taken as the AS_PATH
1266 * otherwise
1267 * the Aggregator shall be ignored and the
1268 * AS4_AGGREGATOR shall be taken as the
1269 * Aggregating node and the AS_PATH is to be
1270 * constructed "as in all other cases"
1271 */
1272 if ( attre->aggregator_as != BGP_AS_TRANS )
1273 {
1274 /* ignore */
1275 if ( BGP_DEBUG(as4, AS4))
1276 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1277 " send AGGREGATOR != AS_TRANS and"
1278 " AS4_AGGREGATOR, so ignore"
1279 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1280 ignore_as4_path = 1;
1281 }
1282 else
1283 {
1284 /* "New_aggregator shall be taken as aggregator" */
1285 attre->aggregator_as = as4_aggregator;
1286 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1287 }
1288 }
1289 else
1290 {
1291 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1292 * That is bogus - but reading the conditions
1293 * we have to handle AS4_AGGREGATOR as if it were
1294 * AGGREGATOR in that case
1295 */
1296 if ( BGP_DEBUG(as4, AS4))
1297 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1298 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1299 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001300 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001301 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1302 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1303 }
1304 }
1305
1306 /* need to reconcile NEW_AS_PATH and AS_PATH */
1307 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1308 {
1309 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1310 aspath_unintern (attr->aspath);
1311 attr->aspath = aspath_intern (newpath);
1312 }
1313 return 0;
1314}
1315
paul718e3742002-12-13 20:15:29 +00001316/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001317static int
paul718e3742002-12-13 20:15:29 +00001318bgp_attr_community (struct peer *peer, bgp_size_t length,
1319 struct attr *attr, u_char flag)
1320{
1321 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001322 {
1323 attr->community = NULL;
1324 return 0;
1325 }
Paul Jakmafc097162010-12-05 17:17:26 +00001326
1327 attr->community =
1328 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1329
1330 /* XXX: fix community_parse to use stream API and remove this */
1331 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001332
Paul Jakmafc097162010-12-05 17:17:26 +00001333 if (!attr->community)
1334 return -1;
1335
paul718e3742002-12-13 20:15:29 +00001336 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1337
1338 return 0;
1339}
1340
1341/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001342static int
paul718e3742002-12-13 20:15:29 +00001343bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1344 struct attr *attr, u_char flag)
1345{
1346 if (length != 4)
1347 {
1348 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1349
1350 bgp_notify_send (peer,
1351 BGP_NOTIFY_UPDATE_ERR,
1352 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1353 return -1;
1354 }
1355
Paul Jakmafb982c22007-05-04 20:15:47 +00001356 (bgp_attr_extra_get (attr))->originator_id.s_addr
1357 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001358
1359 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1360
1361 return 0;
1362}
1363
1364/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001365static int
paul718e3742002-12-13 20:15:29 +00001366bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1367 struct attr *attr, u_char flag)
1368{
1369 /* Check length. */
1370 if (length % 4)
1371 {
1372 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1373
1374 bgp_notify_send (peer,
1375 BGP_NOTIFY_UPDATE_ERR,
1376 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1377 return -1;
1378 }
1379
Paul Jakmafb982c22007-05-04 20:15:47 +00001380 (bgp_attr_extra_get (attr))->cluster
1381 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001382
paul9985f832005-02-09 15:51:56 +00001383 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001384
1385 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1386
1387 return 0;
1388}
1389
1390/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001391int
paul718e3742002-12-13 20:15:29 +00001392bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1393 struct bgp_nlri *mp_update)
1394{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001395 afi_t afi;
1396 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001397 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001398 size_t start;
paul718e3742002-12-13 20:15:29 +00001399 int ret;
1400 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001401 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001402
1403 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001404 s = BGP_INPUT(peer);
1405 start = stream_get_getp(s);
1406
1407 /* safe to read statically sized header? */
1408#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001409#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001410 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001411 {
1412 zlog_info ("%s: %s sent invalid length, %lu",
1413 __func__, peer->host, (unsigned long)length);
1414 return -1;
1415 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001416
paul718e3742002-12-13 20:15:29 +00001417 /* Load AFI, SAFI. */
1418 afi = stream_getw (s);
1419 safi = stream_getc (s);
1420
1421 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001422 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001423
Paul Jakma03292802008-06-07 20:37:10 +00001424 if (LEN_LEFT < attre->mp_nexthop_len)
1425 {
1426 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1427 __func__, peer->host, attre->mp_nexthop_len);
1428 return -1;
1429 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001430
paul718e3742002-12-13 20:15:29 +00001431 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001432 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001433 {
1434 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001435 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001436 /* Probably needed for RFC 2283 */
1437 if (attr->nexthop.s_addr == 0)
1438 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001439 break;
1440 case 12:
1441 {
1442 u_int32_t rd_high;
1443 u_int32_t rd_low;
1444
1445 rd_high = stream_getl (s);
1446 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001447 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001448 }
1449 break;
1450#ifdef HAVE_IPV6
1451 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001452 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001453 break;
1454 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 stream_get (&attre->mp_nexthop_global, s, 16);
1456 stream_get (&attre->mp_nexthop_local, s, 16);
1457 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001458 {
1459 char buf1[INET6_ADDRSTRLEN];
1460 char buf2[INET6_ADDRSTRLEN];
1461
1462 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001463 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 +00001464 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001465 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001466 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001467 buf2, INET6_ADDRSTRLEN));
1468
Paul Jakmafb982c22007-05-04 20:15:47 +00001469 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001470 }
1471 break;
1472#endif /* HAVE_IPV6 */
1473 default:
Paul Jakma03292802008-06-07 20:37:10 +00001474 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1475 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001476 return -1;
paul718e3742002-12-13 20:15:29 +00001477 }
1478
Paul Jakma03292802008-06-07 20:37:10 +00001479 if (!LEN_LEFT)
1480 {
1481 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1482 __func__, peer->host);
1483 return -1;
1484 }
paul718e3742002-12-13 20:15:29 +00001485
Paul Jakma6e4ab122007-04-10 19:36:48 +00001486 {
1487 u_char val;
1488 if ((val = stream_getc (s)))
1489 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1490 peer->host, val);
1491 }
1492
1493 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001494 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001495 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001496 {
1497 zlog_info ("%s: (%s) Failed to read NLRI",
1498 __func__, peer->host);
1499 return -1;
1500 }
paul718e3742002-12-13 20:15:29 +00001501
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001502 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001503 {
1504 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001505 if (ret < 0)
1506 {
1507 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1508 __func__, peer->host);
1509 return -1;
1510 }
paul718e3742002-12-13 20:15:29 +00001511 }
1512
1513 mp_update->afi = afi;
1514 mp_update->safi = safi;
1515 mp_update->nlri = stream_pnt (s);
1516 mp_update->length = nlri_len;
1517
paul9985f832005-02-09 15:51:56 +00001518 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001519
1520 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001521#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001522}
1523
1524/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001525int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001526bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001527 struct bgp_nlri *mp_withdraw)
1528{
1529 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001530 afi_t afi;
1531 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001532 u_int16_t withdraw_len;
1533 int ret;
1534
1535 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001536
1537#define BGP_MP_UNREACH_MIN_SIZE 3
1538 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1539 return -1;
1540
paul718e3742002-12-13 20:15:29 +00001541 afi = stream_getw (s);
1542 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001543
1544 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001545
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001546 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001547 {
1548 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1549 if (ret < 0)
1550 return -1;
1551 }
1552
1553 mp_withdraw->afi = afi;
1554 mp_withdraw->safi = safi;
1555 mp_withdraw->nlri = stream_pnt (s);
1556 mp_withdraw->length = withdraw_len;
1557
paul9985f832005-02-09 15:51:56 +00001558 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001559
1560 return 0;
1561}
1562
1563/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001564static int
paul718e3742002-12-13 20:15:29 +00001565bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1566 struct attr *attr, u_char flag)
1567{
1568 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001569 {
1570 if (attr->extra)
1571 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001572 /* Empty extcomm doesn't seem to be invalid per se */
1573 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001574 }
Paul Jakmafc097162010-12-05 17:17:26 +00001575
1576 (bgp_attr_extra_get (attr))->ecommunity =
1577 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1578 /* XXX: fix ecommunity_parse to use stream API */
1579 stream_forward_getp (peer->ibuf, length);
1580
1581 if (!attr->extra->ecommunity)
1582 return -1;
1583
paul718e3742002-12-13 20:15:29 +00001584 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1585
1586 return 0;
1587}
1588
1589/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001590static int
paul718e3742002-12-13 20:15:29 +00001591bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1592 u_char type, bgp_size_t length, u_char *startp)
1593{
1594 bgp_size_t total;
1595 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001596 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001597
hassof4184462005-02-01 20:13:16 +00001598 if (BGP_DEBUG (normal, NORMAL))
1599 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1600 peer->host, type, length);
1601
paul718e3742002-12-13 20:15:29 +00001602 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001603 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001604 "Unknown attribute type %d length %d is received", type, length);
1605
1606 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001607 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001608
1609 /* Adjest total length to include type and length. */
1610 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1611
1612 /* If any of the mandatory well-known attributes are not recognized,
1613 then the Error Subcode is set to Unrecognized Well-known
1614 Attribute. The Data field contains the unrecognized attribute
1615 (type, length and value). */
1616 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1617 {
1618 /* Adjust startp to do not include flag value. */
1619 bgp_notify_send_with_data (peer,
1620 BGP_NOTIFY_UPDATE_ERR,
1621 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1622 startp, total);
1623 return -1;
1624 }
1625
1626 /* Unrecognized non-transitive optional attributes must be quietly
1627 ignored and not passed along to other BGP peers. */
1628 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1629 return 0;
1630
1631 /* If a path with recognized transitive optional attribute is
1632 accepted and passed along to other BGP peers and the Partial bit
1633 in the Attribute Flags octet is set to 1 by some previous AS, it
1634 is not set back to 0 by the current AS. */
1635 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1636
1637 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001638 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001639 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001640
Paul Jakmafb982c22007-05-04 20:15:47 +00001641 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001642
1643 if (transit->val)
1644 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1645 transit->length + total);
1646 else
1647 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1648
1649 memcpy (transit->val + transit->length, startp, total);
1650 transit->length += total;
1651
1652 return 0;
1653}
1654
1655/* Read attribute of update packet. This function is called from
1656 bgp_update() in bgpd.c. */
1657int
1658bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1659 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1660{
1661 int ret;
1662 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001663 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001664 bgp_size_t length;
1665 u_char *startp, *endp;
1666 u_char *attr_endp;
1667 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001668 /* we need the as4_path only until we have synthesized the as_path with it */
1669 /* same goes for as4_aggregator */
1670 struct aspath *as4_path = NULL;
1671 as_t as4_aggregator = 0;
1672 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001673
1674 /* Initialize bitmap. */
1675 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1676
1677 /* End pointer of BGP attribute. */
1678 endp = BGP_INPUT_PNT (peer) + size;
1679
1680 /* Get attributes to the end of attribute length. */
1681 while (BGP_INPUT_PNT (peer) < endp)
1682 {
1683 /* Check remaining length check.*/
1684 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1685 {
gdtc29fdba2004-12-09 14:46:46 +00001686 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001687 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001688 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001689 peer->host,
1690 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001691
1692 bgp_notify_send (peer,
1693 BGP_NOTIFY_UPDATE_ERR,
1694 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1695 return -1;
1696 }
1697
1698 /* Fetch attribute flag and type. */
1699 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001700 /* "The lower-order four bits of the Attribute Flags octet are
1701 unused. They MUST be zero when sent and MUST be ignored when
1702 received." */
1703 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001704 type = stream_getc (BGP_INPUT (peer));
1705
Paul Jakma370b64a2007-12-22 16:49:52 +00001706 /* Check whether Extended-Length applies and is in bounds */
1707 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1708 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1709 {
1710 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001711 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001712 peer->host,
1713 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1714
1715 bgp_notify_send (peer,
1716 BGP_NOTIFY_UPDATE_ERR,
1717 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1718 return -1;
1719 }
1720
paul718e3742002-12-13 20:15:29 +00001721 /* Check extended attribue length bit. */
1722 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1723 length = stream_getw (BGP_INPUT (peer));
1724 else
1725 length = stream_getc (BGP_INPUT (peer));
1726
1727 /* If any attribute appears more than once in the UPDATE
1728 message, then the Error Subcode is set to Malformed Attribute
1729 List. */
1730
1731 if (CHECK_BITMAP (seen, type))
1732 {
1733 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001734 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001735 peer->host, type);
1736
1737 bgp_notify_send (peer,
1738 BGP_NOTIFY_UPDATE_ERR,
1739 BGP_NOTIFY_UPDATE_MAL_ATTR);
1740 return -1;
1741 }
1742
1743 /* Set type to bitmap to check duplicate attribute. `type' is
1744 unsigned char so it never overflow bitmap range. */
1745
1746 SET_BITMAP (seen, type);
1747
1748 /* Overflow check. */
1749 attr_endp = BGP_INPUT_PNT (peer) + length;
1750
1751 if (attr_endp > endp)
1752 {
1753 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001754 "%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 +00001755 bgp_notify_send (peer,
1756 BGP_NOTIFY_UPDATE_ERR,
1757 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1758 return -1;
1759 }
1760
1761 /* OK check attribute and store it's value. */
1762 switch (type)
1763 {
1764 case BGP_ATTR_ORIGIN:
1765 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1766 break;
1767 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001768 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1769 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001770 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001771 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001772 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1773 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001774 break;
paul718e3742002-12-13 20:15:29 +00001775 case BGP_ATTR_NEXT_HOP:
1776 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1777 break;
1778 case BGP_ATTR_MULTI_EXIT_DISC:
1779 ret = bgp_attr_med (peer, length, attr, flag, startp);
1780 break;
1781 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001782 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001783 break;
1784 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001785 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001786 break;
1787 case BGP_ATTR_AGGREGATOR:
1788 ret = bgp_attr_aggregator (peer, length, attr, flag);
1789 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001790 case BGP_ATTR_AS4_AGGREGATOR:
1791 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1792 break;
paul718e3742002-12-13 20:15:29 +00001793 case BGP_ATTR_COMMUNITIES:
1794 ret = bgp_attr_community (peer, length, attr, flag);
1795 break;
1796 case BGP_ATTR_ORIGINATOR_ID:
1797 ret = bgp_attr_originator_id (peer, length, attr, flag);
1798 break;
1799 case BGP_ATTR_CLUSTER_LIST:
1800 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1801 break;
1802 case BGP_ATTR_MP_REACH_NLRI:
1803 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1804 break;
1805 case BGP_ATTR_MP_UNREACH_NLRI:
1806 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1807 break;
1808 case BGP_ATTR_EXT_COMMUNITIES:
1809 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1810 break;
1811 default:
1812 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1813 break;
1814 }
1815
1816 /* If error occured immediately return to the caller. */
1817 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001818 {
1819 zlog (peer->log, LOG_WARNING,
1820 "%s: Attribute %s, parse error",
1821 peer->host,
1822 LOOKUP (attr_str, type));
1823 bgp_notify_send (peer,
1824 BGP_NOTIFY_UPDATE_ERR,
1825 BGP_NOTIFY_UPDATE_MAL_ATTR);
1826 return ret;
1827 }
paul718e3742002-12-13 20:15:29 +00001828
1829 /* Check the fetched length. */
1830 if (BGP_INPUT_PNT (peer) != attr_endp)
1831 {
1832 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001833 "%s: BGP attribute %s, fetch error",
1834 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001835 bgp_notify_send (peer,
1836 BGP_NOTIFY_UPDATE_ERR,
1837 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1838 return -1;
1839 }
1840 }
1841
1842 /* Check final read pointer is same as end pointer. */
1843 if (BGP_INPUT_PNT (peer) != endp)
1844 {
1845 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001846 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001847 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001848 bgp_notify_send (peer,
1849 BGP_NOTIFY_UPDATE_ERR,
1850 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1851 return -1;
1852 }
1853
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001854 /*
1855 * At this place we can see whether we got AS4_PATH and/or
1856 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1857 * We can not do this before we've read all attributes because
1858 * the as4 handling does not say whether AS4_PATH has to be sent
1859 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1860 * in relationship to AGGREGATOR.
1861 * So, to be defensive, we are not relying on any order and read
1862 * all attributes first, including these 32bit ones, and now,
1863 * afterwards, we look what and if something is to be done for as4.
1864 */
1865 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1866 as4_aggregator, &as4_aggregator_addr))
1867 return -1;
1868
1869 /* At this stage, we have done all fiddling with as4, and the
1870 * resulting info is in attr->aggregator resp. attr->aspath
1871 * so we can chuck as4_aggregator and as4_path alltogether in
1872 * order to save memory
1873 */
1874 if ( as4_path )
1875 {
1876 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1877 as4_path = NULL;
1878 /* The flag that we got this is still there, but that does not
1879 * do any trouble
1880 */
1881 }
1882 /*
1883 * The "rest" of the code does nothing with as4_aggregator.
1884 * there is no memory attached specifically which is not part
1885 * of the attr.
1886 * so ignoring just means do nothing.
1887 */
1888 /*
1889 * Finally do the checks on the aspath we did not do yet
1890 * because we waited for a potentially synthesized aspath.
1891 */
1892 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1893 {
1894 ret = bgp_attr_aspath_check( peer, attr );
1895 if ( ret < 0 )
1896 return ret;
1897 }
1898
paul718e3742002-12-13 20:15:29 +00001899 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001900 if (attr->extra && attr->extra->transit)
1901 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001902
1903 return 0;
1904}
1905
1906/* Well-known attribute check. */
1907int
1908bgp_attr_check (struct peer *peer, struct attr *attr)
1909{
1910 u_char type = 0;
1911
1912 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1913 type = BGP_ATTR_ORIGIN;
1914
1915 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1916 type = BGP_ATTR_AS_PATH;
1917
1918 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1919 type = BGP_ATTR_NEXT_HOP;
1920
1921 if (peer_sort (peer) == BGP_PEER_IBGP
1922 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1923 type = BGP_ATTR_LOCAL_PREF;
1924
1925 if (type)
1926 {
1927 zlog (peer->log, LOG_WARNING,
1928 "%s Missing well-known attribute %d.",
1929 peer->host, type);
1930 bgp_notify_send_with_data (peer,
1931 BGP_NOTIFY_UPDATE_ERR,
1932 BGP_NOTIFY_UPDATE_MISS_ATTR,
1933 &type, 1);
1934 return -1;
1935 }
1936 return 0;
1937}
1938
1939int stream_put_prefix (struct stream *, struct prefix *);
1940
1941/* Make attribute packet. */
1942bgp_size_t
1943bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1944 struct stream *s, struct attr *attr, struct prefix *p,
1945 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001946 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001947{
paulfe69a502005-09-10 16:55:02 +00001948 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001949 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001950 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001951 int send_as4_path = 0;
1952 int send_as4_aggregator = 0;
1953 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001954
1955 if (! bgp)
1956 bgp = bgp_get_default ();
1957
1958 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001959 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001960
1961 /* Origin attribute. */
1962 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1963 stream_putc (s, BGP_ATTR_ORIGIN);
1964 stream_putc (s, 1);
1965 stream_putc (s, attr->origin);
1966
1967 /* AS path attribute. */
1968
1969 /* If remote-peer is EBGP */
1970 if (peer_sort (peer) == BGP_PEER_EBGP
1971 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001972 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001973 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001974 {
1975 aspath = aspath_dup (attr->aspath);
1976
1977 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1978 {
1979 /* Strip the confed info, and then stuff our path CONFED_ID
1980 on the front */
1981 aspath = aspath_delete_confed_seq (aspath);
1982 aspath = aspath_add_seq (aspath, bgp->confed_id);
1983 }
1984 else
1985 {
1986 aspath = aspath_add_seq (aspath, peer->local_as);
1987 if (peer->change_local_as)
1988 aspath = aspath_add_seq (aspath, peer->change_local_as);
1989 }
1990 }
1991 else if (peer_sort (peer) == BGP_PEER_CONFED)
1992 {
1993 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1994 aspath = aspath_dup (attr->aspath);
1995 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1996 }
1997 else
1998 aspath = attr->aspath;
1999
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002000 /* If peer is not AS4 capable, then:
2001 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2002 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2003 * types are in it (i.e. exclude them if they are there)
2004 * AND do this only if there is at least one asnum > 65535 in the path!
2005 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2006 * all ASnums > 65535 to BGP_AS_TRANS
2007 */
paul718e3742002-12-13 20:15:29 +00002008
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002009 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2010 stream_putc (s, BGP_ATTR_AS_PATH);
2011 aspath_sizep = stream_get_endp (s);
2012 stream_putw (s, 0);
2013 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2014
2015 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2016 * in the path
2017 */
2018 if (!use32bit && aspath_has_as4 (aspath))
2019 send_as4_path = 1; /* we'll do this later, at the correct place */
2020
paul718e3742002-12-13 20:15:29 +00002021 /* Nexthop attribute. */
2022 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2023 {
2024 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2025 stream_putc (s, BGP_ATTR_NEXT_HOP);
2026 stream_putc (s, 4);
2027 if (safi == SAFI_MPLS_VPN)
2028 {
2029 if (attr->nexthop.s_addr == 0)
2030 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2031 else
2032 stream_put_ipv4 (s, attr->nexthop.s_addr);
2033 }
2034 else
2035 stream_put_ipv4 (s, attr->nexthop.s_addr);
2036 }
2037
2038 /* MED attribute. */
2039 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2040 {
2041 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2042 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2043 stream_putc (s, 4);
2044 stream_putl (s, attr->med);
2045 }
2046
2047 /* Local preference. */
2048 if (peer_sort (peer) == BGP_PEER_IBGP ||
2049 peer_sort (peer) == BGP_PEER_CONFED)
2050 {
2051 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2052 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2053 stream_putc (s, 4);
2054 stream_putl (s, attr->local_pref);
2055 }
2056
2057 /* Atomic aggregate. */
2058 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2059 {
2060 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2061 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2062 stream_putc (s, 0);
2063 }
2064
2065 /* Aggregator. */
2066 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2067 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002068 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002069
2070 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002071 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2072 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002073
2074 if (use32bit)
2075 {
2076 /* AS4 capable peer */
2077 stream_putc (s, 8);
2078 stream_putl (s, attr->extra->aggregator_as);
2079 }
2080 else
2081 {
2082 /* 2-byte AS peer */
2083 stream_putc (s, 6);
2084
2085 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2086 if ( attr->extra->aggregator_as > 65535 )
2087 {
2088 stream_putw (s, BGP_AS_TRANS);
2089
2090 /* we have to send AS4_AGGREGATOR, too.
2091 * we'll do that later in order to send attributes in ascending
2092 * order.
2093 */
2094 send_as4_aggregator = 1;
2095 }
2096 else
2097 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2098 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002099 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002100 }
2101
2102 /* Community attribute. */
2103 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2104 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2105 {
2106 if (attr->community->size * 4 > 255)
2107 {
2108 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2109 stream_putc (s, BGP_ATTR_COMMUNITIES);
2110 stream_putw (s, attr->community->size * 4);
2111 }
2112 else
2113 {
2114 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2115 stream_putc (s, BGP_ATTR_COMMUNITIES);
2116 stream_putc (s, attr->community->size * 4);
2117 }
2118 stream_put (s, attr->community->val, attr->community->size * 4);
2119 }
2120
2121 /* Route Reflector. */
2122 if (peer_sort (peer) == BGP_PEER_IBGP
2123 && from
2124 && peer_sort (from) == BGP_PEER_IBGP)
2125 {
2126 /* Originator ID. */
2127 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2128 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2129 stream_putc (s, 4);
2130
2131 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002132 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002133 else
2134 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002135
2136 /* Cluster list. */
2137 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2138 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2139
Paul Jakma9eda90c2007-08-30 13:36:17 +00002140 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002141 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002142 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002143 /* If this peer configuration's parent BGP has cluster_id. */
2144 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2145 stream_put_in_addr (s, &bgp->cluster_id);
2146 else
2147 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002148 stream_put (s, attr->extra->cluster->list,
2149 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002150 }
2151 else
2152 {
2153 stream_putc (s, 4);
2154 /* If this peer configuration's parent BGP has cluster_id. */
2155 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2156 stream_put_in_addr (s, &bgp->cluster_id);
2157 else
2158 stream_put_in_addr (s, &bgp->router_id);
2159 }
2160 }
2161
2162#ifdef HAVE_IPV6
2163 /* If p is IPv6 address put it into attribute. */
2164 if (p->family == AF_INET6)
2165 {
2166 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002167 struct attr_extra *attre = attr->extra;
2168
2169 assert (attr->extra);
2170
paul718e3742002-12-13 20:15:29 +00002171 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2172 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002173 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002174 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002175 stream_putw (s, AFI_IP6); /* AFI */
2176 stream_putc (s, safi); /* SAFI */
2177
Paul Jakmafb982c22007-05-04 20:15:47 +00002178 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002179
Paul Jakmafb982c22007-05-04 20:15:47 +00002180 if (attre->mp_nexthop_len == 16)
2181 stream_put (s, &attre->mp_nexthop_global, 16);
2182 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002183 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002184 stream_put (s, &attre->mp_nexthop_global, 16);
2185 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002186 }
2187
2188 /* SNPA */
2189 stream_putc (s, 0);
2190
paul718e3742002-12-13 20:15:29 +00002191 /* Prefix write. */
2192 stream_put_prefix (s, p);
2193
2194 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002195 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002196 }
2197#endif /* HAVE_IPV6 */
2198
2199 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2200 {
2201 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002202
2203 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2204 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002205 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002206 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002207 stream_putw (s, AFI_IP); /* AFI */
2208 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2209
2210 stream_putc (s, 4);
2211 stream_put_ipv4 (s, attr->nexthop.s_addr);
2212
2213 /* SNPA */
2214 stream_putc (s, 0);
2215
paul718e3742002-12-13 20:15:29 +00002216 /* Prefix write. */
2217 stream_put_prefix (s, p);
2218
2219 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002220 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002221 }
2222
2223 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2224 {
2225 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002226
2227 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2228 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002229 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002230 stream_putc (s, 0); /* Length of this attribute. */
2231 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002232 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002233
2234 stream_putc (s, 12);
2235 stream_putl (s, 0);
2236 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002237 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002238
2239 /* SNPA */
2240 stream_putc (s, 0);
2241
paul718e3742002-12-13 20:15:29 +00002242 /* Tag, RD, Prefix write. */
2243 stream_putc (s, p->prefixlen + 88);
2244 stream_put (s, tag, 3);
2245 stream_put (s, prd->val, 8);
2246 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2247
2248 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002249 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002250 }
2251
2252 /* Extended Communities attribute. */
2253 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2254 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2255 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002256 struct attr_extra *attre = attr->extra;
2257
2258 assert (attre);
2259
2260 if (peer_sort (peer) == BGP_PEER_IBGP
2261 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002262 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002263 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002264 {
2265 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2266 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002267 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002268 }
2269 else
2270 {
2271 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2272 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002273 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002274 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002275 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002276 }
2277 else
2278 {
paul5228ad22004-06-04 17:58:18 +00002279 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002280 int tbit;
2281 int ecom_tr_size = 0;
2282 int i;
2283
Paul Jakmafb982c22007-05-04 20:15:47 +00002284 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002285 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002286 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002287 tbit = *pnt;
2288
2289 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2290 continue;
2291
2292 ecom_tr_size++;
2293 }
2294
2295 if (ecom_tr_size)
2296 {
2297 if (ecom_tr_size * 8 > 255)
2298 {
2299 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2300 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2301 stream_putw (s, ecom_tr_size * 8);
2302 }
2303 else
2304 {
2305 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2306 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2307 stream_putc (s, ecom_tr_size * 8);
2308 }
2309
Paul Jakmafb982c22007-05-04 20:15:47 +00002310 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002311 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002312 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002313 tbit = *pnt;
2314
2315 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2316 continue;
2317
2318 stream_put (s, pnt, 8);
2319 }
2320 }
paul718e3742002-12-13 20:15:29 +00002321 }
paul718e3742002-12-13 20:15:29 +00002322 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002323
2324 if ( send_as4_path )
2325 {
2326 /* If the peer is NOT As4 capable, AND */
2327 /* there are ASnums > 65535 in path THEN
2328 * give out AS4_PATH */
2329
2330 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2331 * path segments!
2332 * Hm, I wonder... confederation things *should* only be at
2333 * the beginning of an aspath, right? Then we should use
2334 * aspath_delete_confed_seq for this, because it is already
2335 * there! (JK)
2336 * Folks, talk to me: what is reasonable here!?
2337 */
2338 aspath = aspath_delete_confed_seq (aspath);
2339
2340 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2341 stream_putc (s, BGP_ATTR_AS4_PATH);
2342 aspath_sizep = stream_get_endp (s);
2343 stream_putw (s, 0);
2344 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2345 }
2346
2347 if (aspath != attr->aspath)
2348 aspath_free (aspath);
2349
2350 if ( send_as4_aggregator )
2351 {
2352 assert (attr->extra);
2353
2354 /* send AS4_AGGREGATOR, at this place */
2355 /* this section of code moved here in order to ensure the correct
2356 * *ascending* order of attributes
2357 */
2358 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2359 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2360 stream_putc (s, 8);
2361 stream_putl (s, attr->extra->aggregator_as);
2362 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2363 }
Paul Jakma41367172007-08-06 15:24:51 +00002364
paul718e3742002-12-13 20:15:29 +00002365 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002366 if (attr->extra && attr->extra->transit)
2367 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002368
2369 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002370 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002371}
2372
2373bgp_size_t
2374bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2375 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002376 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002377{
2378 unsigned long cp;
2379 unsigned long attrlen_pnt;
2380 bgp_size_t size;
2381
paul9985f832005-02-09 15:51:56 +00002382 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002383
2384 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2385 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2386
paul9985f832005-02-09 15:51:56 +00002387 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002388 stream_putc (s, 0); /* Length of this attribute. */
2389
2390 stream_putw (s, family2afi (p->family));
2391
2392 if (safi == SAFI_MPLS_VPN)
2393 {
2394 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002395 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002396
2397 /* prefix. */
2398 stream_putc (s, p->prefixlen + 88);
2399 stream_put (s, tag, 3);
2400 stream_put (s, prd->val, 8);
2401 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2402 }
2403 else
2404 {
2405 /* SAFI */
2406 stream_putc (s, safi);
2407
2408 /* prefix */
2409 stream_put_prefix (s, p);
2410 }
2411
2412 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002413 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002414 stream_putc_at (s, attrlen_pnt, size);
2415
paul9985f832005-02-09 15:51:56 +00002416 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002417}
2418
2419/* Initialization of attribute. */
2420void
paulfe69a502005-09-10 16:55:02 +00002421bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002422{
paul718e3742002-12-13 20:15:29 +00002423 aspath_init ();
2424 attrhash_init ();
2425 community_init ();
2426 ecommunity_init ();
2427 cluster_init ();
2428 transit_init ();
2429}
2430
Chris Caputo228da422009-07-18 05:44:03 +00002431void
2432bgp_attr_finish (void)
2433{
2434 aspath_finish ();
2435 attrhash_finish ();
2436 community_finish ();
2437 ecommunity_finish ();
2438 cluster_finish ();
2439 transit_finish ();
2440}
2441
paul718e3742002-12-13 20:15:29 +00002442/* Make attribute packet. */
2443void
paula3845922003-10-18 01:30:50 +00002444bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2445 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002446{
2447 unsigned long cp;
2448 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002449 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002450 struct aspath *aspath;
2451
2452 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002453 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002454
2455 /* Place holder of length. */
2456 stream_putw (s, 0);
2457
2458 /* Origin attribute. */
2459 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2460 stream_putc (s, BGP_ATTR_ORIGIN);
2461 stream_putc (s, 1);
2462 stream_putc (s, attr->origin);
2463
2464 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002465
2466 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2467 stream_putc (s, BGP_ATTR_AS_PATH);
2468 aspath_lenp = stream_get_endp (s);
2469 stream_putw (s, 0);
2470
2471 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002472
2473 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002474 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2475 if(prefix != NULL
2476#ifdef HAVE_IPV6
2477 && prefix->family != AF_INET6
2478#endif /* HAVE_IPV6 */
2479 )
2480 {
2481 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2482 stream_putc (s, BGP_ATTR_NEXT_HOP);
2483 stream_putc (s, 4);
2484 stream_put_ipv4 (s, attr->nexthop.s_addr);
2485 }
paul718e3742002-12-13 20:15:29 +00002486
2487 /* MED attribute. */
2488 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2489 {
2490 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2491 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2492 stream_putc (s, 4);
2493 stream_putl (s, attr->med);
2494 }
2495
2496 /* Local preference. */
2497 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2498 {
2499 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2500 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2501 stream_putc (s, 4);
2502 stream_putl (s, attr->local_pref);
2503 }
2504
2505 /* Atomic aggregate. */
2506 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2507 {
2508 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2509 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2510 stream_putc (s, 0);
2511 }
2512
2513 /* Aggregator. */
2514 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2515 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002516 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002517 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2518 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002519 stream_putc (s, 8);
2520 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002521 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002522 }
2523
2524 /* Community attribute. */
2525 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2526 {
2527 if (attr->community->size * 4 > 255)
2528 {
2529 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2530 stream_putc (s, BGP_ATTR_COMMUNITIES);
2531 stream_putw (s, attr->community->size * 4);
2532 }
2533 else
2534 {
2535 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2536 stream_putc (s, BGP_ATTR_COMMUNITIES);
2537 stream_putc (s, attr->community->size * 4);
2538 }
2539 stream_put (s, attr->community->val, attr->community->size * 4);
2540 }
2541
paula3845922003-10-18 01:30:50 +00002542#ifdef HAVE_IPV6
2543 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002544 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2545 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002546 {
2547 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002548 struct attr_extra *attre = attr->extra;
2549
paula3845922003-10-18 01:30:50 +00002550 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2551 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002552 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002553
2554 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002555 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002556 stream_putw(s, AFI_IP6); /* AFI */
2557 stream_putc(s, SAFI_UNICAST); /* SAFI */
2558
2559 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002560 stream_putc(s, attre->mp_nexthop_len);
2561 stream_put(s, &attre->mp_nexthop_global, 16);
2562 if (attre->mp_nexthop_len == 32)
2563 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002564
2565 /* SNPA */
2566 stream_putc(s, 0);
2567
2568 /* Prefix */
2569 stream_put_prefix(s, prefix);
2570
2571 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002572 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002573 }
2574#endif /* HAVE_IPV6 */
2575
paul718e3742002-12-13 20:15:29 +00002576 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002577 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002578 stream_putw_at (s, cp, len);
2579}