blob: c76b22b343065ba511702c74eccaed8e9f4b5531 [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" },
Denis Ovsienko452db842011-10-10 16:52:20 +040053 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
paul718e3742002-12-13 20:15:29 +000054 { 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). */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400715 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400716 {
717 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
718 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
719 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
720 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
721 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
722 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
723 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
724 return -1;
725 }
paul718e3742002-12-13 20:15:29 +0000726
727 /* If any recognized attribute has Attribute Length that conflicts
728 with the expected length (based on the attribute type code), then
729 the Error Subcode is set to Attribute Length Error. The Data
730 field contains the erroneous attribute (type, length and
731 value). */
732 if (length != 1)
733 {
734 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
735 length);
736 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
737 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
738 startp, total);
739 return -1;
740 }
741
742 /* Fetch origin attribute. */
743 attr->origin = stream_getc (BGP_INPUT (peer));
744
745 /* If the ORIGIN attribute has an undefined value, then the Error
746 Subcode is set to Invalid Origin Attribute. The Data field
747 contains the unrecognized attribute (type, length and value). */
748 if ((attr->origin != BGP_ORIGIN_IGP)
749 && (attr->origin != BGP_ORIGIN_EGP)
750 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
751 {
752 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
753 attr->origin);
754
755 bgp_notify_send_with_data (peer,
756 BGP_NOTIFY_UPDATE_ERR,
757 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
758 startp, total);
759 return -1;
760 }
761
762 /* Set oring attribute flag. */
763 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
764
765 return 0;
766}
Chris Hallcddb8112010-08-09 22:31:37 +0400767/* Parse AS path information. This function is wrapper of aspath_parse.
768 *
769 * Parses AS_PATH or AS4_PATH.
770 *
771 * Returns: if valid: address of struct aspath in the hash of known aspaths,
772 * with reference count incremented.
773 * else: NULL
774 *
775 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
776 * have segments == NULL and str == zero length string (unique).
777 */
778static struct aspath *
paul718e3742002-12-13 20:15:29 +0000779bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400780 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000781{
Chris Hallcddb8112010-08-09 22:31:37 +0400782 u_char require ;
783 struct aspath *asp ;
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400784 bgp_size_t total;
785
786 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000787
Chris Hallcddb8112010-08-09 22:31:37 +0400788 /* Check the attribute flags */
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400789 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
790 {
791 zlog (peer->log, LOG_ERR,
792 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
793 bgp_notify_send_with_data (peer,
794 BGP_NOTIFY_UPDATE_ERR,
795 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
796 startp, total);
797 return NULL;
798 }
799
Chris Hallcddb8112010-08-09 22:31:37 +0400800 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
801 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000802
Chris Hallcddb8112010-08-09 22:31:37 +0400803 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000804 {
Chris Hallcddb8112010-08-09 22:31:37 +0400805 const char* path_type ;
Chris Hallcddb8112010-08-09 22:31:37 +0400806
807 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
808
809 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000810 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400811 "%s attribute flag isn't transitive %d", path_type, flag) ;
812
813 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
814 zlog (peer->log, LOG_ERR,
815 "%s attribute flag must %sbe optional %d", path_type,
816 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
817
paul718e3742002-12-13 20:15:29 +0000818 bgp_notify_send_with_data (peer,
819 BGP_NOTIFY_UPDATE_ERR,
820 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
821 startp, total);
paul718e3742002-12-13 20:15:29 +0000822
Chris Hallcddb8112010-08-09 22:31:37 +0400823 return NULL ;
824 } ;
825
826 /* Parse the AS_PATH/AS4_PATH body.
827 *
828 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
829 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000830 */
Chris Hallcddb8112010-08-09 22:31:37 +0400831 asp = aspath_parse (peer->ibuf, length,
832 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000833
Chris Hallcddb8112010-08-09 22:31:37 +0400834 if (asp != NULL)
835 {
836 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
837 : BGP_ATTR_AS_PATH) ;
838 }
839 else
paul718e3742002-12-13 20:15:29 +0000840 {
841 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400842
843 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000844 bgp_notify_send (peer,
845 BGP_NOTIFY_UPDATE_ERR,
846 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400847 } ;
paul718e3742002-12-13 20:15:29 +0000848
Chris Hallcddb8112010-08-09 22:31:37 +0400849 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000850}
851
852static int bgp_attr_aspath_check( struct peer *peer,
853 struct attr *attr)
854{
855 /* These checks were part of bgp_attr_aspath, but with
856 * as4 we should to check aspath things when
857 * aspath synthesizing with as4_path has already taken place.
858 * Otherwise we check ASPATH and use the synthesized thing, and that is
859 * not right.
860 * So do the checks later, i.e. here
861 */
862 struct bgp *bgp = peer->bgp;
863 struct aspath *aspath;
864
paul718e3742002-12-13 20:15:29 +0000865 bgp = peer->bgp;
866
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300867 /* Confederation sanity check. */
868 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
869 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
870 {
871 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
872 bgp_notify_send (peer,
873 BGP_NOTIFY_UPDATE_ERR,
874 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
875 return -1;
876 }
877
paul718e3742002-12-13 20:15:29 +0000878 /* First AS check for EBGP. */
879 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
880 {
881 if (peer_sort (peer) == BGP_PEER_EBGP
882 && ! aspath_firstas_check (attr->aspath, peer->as))
883 {
884 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400885 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000886 bgp_notify_send (peer,
887 BGP_NOTIFY_UPDATE_ERR,
888 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
889 return -1;
890 }
891 }
892
893 /* local-as prepend */
894 if (peer->change_local_as &&
895 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
896 {
897 aspath = aspath_dup (attr->aspath);
898 aspath = aspath_add_seq (aspath, peer->change_local_as);
899 aspath_unintern (attr->aspath);
900 attr->aspath = aspath_intern (aspath);
901 }
902
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903 return 0;
904
905}
906
paul718e3742002-12-13 20:15:29 +0000907/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000908static int
paul718e3742002-12-13 20:15:29 +0000909bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
910 struct attr *attr, u_char flag, u_char *startp)
911{
912 bgp_size_t total;
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400913 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000914
915 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
916
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400917 /* Flags check. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400918 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400919 {
920 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
921 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
922 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
923 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
924 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
925 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
926 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
927 return -1;
928 }
paul718e3742002-12-13 20:15:29 +0000929
930 /* Check nexthop attribute length. */
931 if (length != 4)
932 {
933 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
934 length);
935
936 bgp_notify_send_with_data (peer,
937 BGP_NOTIFY_UPDATE_ERR,
938 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
939 startp, total);
940 return -1;
941 }
942
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400943 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
944 attribute must result in a NOTIFICATION message (this is implemented below).
945 At the same time, semantically incorrect NEXT_HOP is more likely to be just
946 logged locally (this is implemented somewhere else). The UPDATE message
947 gets ignored in any of these cases. */
948 nexthop_n = stream_get_ipv4 (peer->ibuf);
949 nexthop_h = ntohl (nexthop_n);
950 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
951 {
952 char buf[INET_ADDRSTRLEN];
953 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
954 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
955 bgp_notify_send_with_data (peer,
956 BGP_NOTIFY_UPDATE_ERR,
957 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
958 startp, total);
959 return -1;
960 }
961
962 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +0000963 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
964
965 return 0;
966}
967
968/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000969static int
paul718e3742002-12-13 20:15:29 +0000970bgp_attr_med (struct peer *peer, bgp_size_t length,
971 struct attr *attr, u_char flag, u_char *startp)
972{
973 bgp_size_t total;
974
975 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
976
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400977 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400978 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400979 {
980 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
981 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
982 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
983 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
984 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
985 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
986 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
987 return -1;
988 }
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400989
paul718e3742002-12-13 20:15:29 +0000990 /* Length check. */
991 if (length != 4)
992 {
993 zlog (peer->log, LOG_ERR,
994 "MED attribute length isn't four [%d]", length);
995
996 bgp_notify_send_with_data (peer,
997 BGP_NOTIFY_UPDATE_ERR,
998 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
999 startp, total);
1000 return -1;
1001 }
1002
1003 attr->med = stream_getl (peer->ibuf);
1004
1005 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1006
1007 return 0;
1008}
1009
1010/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001011static int
paul718e3742002-12-13 20:15:29 +00001012bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001013 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001014{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001015 bgp_size_t total;
1016
1017 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1018 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001019 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001020 {
1021 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1022 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1023 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1024 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1025 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1026 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1027 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1028 return -1;
1029 }
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001030
paul718e3742002-12-13 20:15:29 +00001031 /* If it is contained in an UPDATE message that is received from an
1032 external peer, then this attribute MUST be ignored by the
1033 receiving speaker. */
1034 if (peer_sort (peer) == BGP_PEER_EBGP)
1035 {
paul9985f832005-02-09 15:51:56 +00001036 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001037 return 0;
1038 }
1039
1040 if (length == 4)
1041 attr->local_pref = stream_getl (peer->ibuf);
1042 else
1043 attr->local_pref = 0;
1044
1045 /* Set atomic aggregate flag. */
1046 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1047
1048 return 0;
1049}
1050
1051/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001052static int
paul718e3742002-12-13 20:15:29 +00001053bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001054 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001055{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001056 bgp_size_t total;
1057
1058 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1059 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001060 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001061 {
1062 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1063 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1064 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1065 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1066 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1067 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1068 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1069 return -1;
1070 }
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001071
1072 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001073 if (length != 0)
1074 {
1075 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1076
1077 bgp_notify_send (peer,
1078 BGP_NOTIFY_UPDATE_ERR,
1079 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1080 return -1;
1081 }
1082
1083 /* Set atomic aggregate flag. */
1084 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1085
1086 return 0;
1087}
1088
1089/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001090static int
paul718e3742002-12-13 20:15:29 +00001091bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1092 struct attr *attr, u_char flag)
1093{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001094 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001095 struct attr_extra *attre = bgp_attr_extra_get (attr);
1096
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001097 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1098 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1099 wantedlen = 8;
1100
1101 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001102 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001103 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001104
1105 bgp_notify_send (peer,
1106 BGP_NOTIFY_UPDATE_ERR,
1107 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1108 return -1;
1109 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001110
1111 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1112 attre->aggregator_as = stream_getl (peer->ibuf);
1113 else
1114 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001115 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001116
1117 /* Set atomic aggregate flag. */
1118 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1119
1120 return 0;
1121}
1122
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001123/* New Aggregator attribute */
1124static int
1125bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1126 struct attr *attr, as_t *as4_aggregator_as,
1127 struct in_addr *as4_aggregator_addr)
1128{
1129 if (length != 8)
1130 {
1131 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1132
1133 bgp_notify_send (peer,
1134 BGP_NOTIFY_UPDATE_ERR,
1135 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1136 return -1;
1137 }
1138 *as4_aggregator_as = stream_getl (peer->ibuf);
1139 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1140
1141 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1142
1143 return 0;
1144}
1145
1146/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1147 */
1148static int
1149bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1150 struct aspath *as4_path, as_t as4_aggregator,
1151 struct in_addr *as4_aggregator_addr)
1152{
1153 int ignore_as4_path = 0;
1154 struct aspath *newpath;
1155 struct attr_extra *attre = attr->extra;
1156
1157 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1158 {
1159 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1160 * if given.
1161 * It is worth a warning though, because the peer really
1162 * should not send them
1163 */
1164 if (BGP_DEBUG(as4, AS4))
1165 {
1166 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1167 zlog_debug ("[AS4] %s %s AS4_PATH",
1168 peer->host, "AS4 capable peer, yet it sent");
1169
1170 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1171 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1172 peer->host, "AS4 capable peer, yet it sent");
1173 }
1174
1175 return 0;
1176 }
1177
1178 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1179 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1180 {
1181 /* Hu? This is not supposed to happen at all!
1182 * got as4_path and no aspath,
1183 * This should already
1184 * have been handled by 'well known attributes missing'
1185 * But... yeah, paranoia
1186 * Take this as a "malformed attribute"
1187 */
1188 zlog (peer->log, LOG_ERR,
1189 "%s BGP not AS4 capable peer sent AS4_PATH but"
1190 " no AS_PATH, cant do anything here", peer->host);
1191 bgp_notify_send (peer,
1192 BGP_NOTIFY_UPDATE_ERR,
1193 BGP_NOTIFY_UPDATE_MAL_ATTR);
1194 return -1;
1195 }
1196
1197 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1198 * because that may override AS4_PATH
1199 */
1200 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1201 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001202 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1203 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001204 assert (attre);
1205
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001206 /* received both.
1207 * if the as_number in aggregator is not AS_TRANS,
1208 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1209 * and the Aggregator shall be taken as
1210 * info on the aggregating node, and the AS_PATH
1211 * shall be taken as the AS_PATH
1212 * otherwise
1213 * the Aggregator shall be ignored and the
1214 * AS4_AGGREGATOR shall be taken as the
1215 * Aggregating node and the AS_PATH is to be
1216 * constructed "as in all other cases"
1217 */
1218 if ( attre->aggregator_as != BGP_AS_TRANS )
1219 {
1220 /* ignore */
1221 if ( BGP_DEBUG(as4, AS4))
1222 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1223 " send AGGREGATOR != AS_TRANS and"
1224 " AS4_AGGREGATOR, so ignore"
1225 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1226 ignore_as4_path = 1;
1227 }
1228 else
1229 {
1230 /* "New_aggregator shall be taken as aggregator" */
1231 attre->aggregator_as = as4_aggregator;
1232 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1233 }
1234 }
1235 else
1236 {
1237 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1238 * That is bogus - but reading the conditions
1239 * we have to handle AS4_AGGREGATOR as if it were
1240 * AGGREGATOR in that case
1241 */
1242 if ( BGP_DEBUG(as4, AS4))
1243 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1244 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1245 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001246 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001247 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1248 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1249 }
1250 }
1251
1252 /* need to reconcile NEW_AS_PATH and AS_PATH */
1253 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1254 {
1255 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1256 aspath_unintern (attr->aspath);
1257 attr->aspath = aspath_intern (newpath);
1258 }
1259 return 0;
1260}
1261
paul718e3742002-12-13 20:15:29 +00001262/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001263static int
paul718e3742002-12-13 20:15:29 +00001264bgp_attr_community (struct peer *peer, bgp_size_t length,
1265 struct attr *attr, u_char flag)
1266{
1267 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001268 {
1269 attr->community = NULL;
1270 return 0;
1271 }
Paul Jakmafc097162010-12-05 17:17:26 +00001272
1273 attr->community =
1274 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1275
1276 /* XXX: fix community_parse to use stream API and remove this */
1277 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001278
Paul Jakmafc097162010-12-05 17:17:26 +00001279 if (!attr->community)
1280 return -1;
1281
paul718e3742002-12-13 20:15:29 +00001282 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1283
1284 return 0;
1285}
1286
1287/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001288static int
paul718e3742002-12-13 20:15:29 +00001289bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienko5de17192011-09-30 15:08:54 +04001290 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001291{
Denis Ovsienko5de17192011-09-30 15:08:54 +04001292 bgp_size_t total;
1293
1294 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1295 /* Flag checks. */
1296 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1297 {
1298 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1299 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1300 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1301 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1302 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1303 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
1304 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1305 return -1;
1306 }
1307 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001308 if (length != 4)
1309 {
1310 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1311
1312 bgp_notify_send (peer,
1313 BGP_NOTIFY_UPDATE_ERR,
1314 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1315 return -1;
1316 }
1317
Paul Jakmafb982c22007-05-04 20:15:47 +00001318 (bgp_attr_extra_get (attr))->originator_id.s_addr
1319 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001320
1321 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1322
1323 return 0;
1324}
1325
1326/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001327static int
paul718e3742002-12-13 20:15:29 +00001328bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001329 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001330{
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001331 bgp_size_t total;
1332
1333 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1334 /* Flag checks. */
1335 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1336 {
1337 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1338 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1339 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1340 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1341 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1342 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
1343 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1344 return -1;
1345 }
paul718e3742002-12-13 20:15:29 +00001346 /* Check length. */
1347 if (length % 4)
1348 {
1349 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1350
1351 bgp_notify_send (peer,
1352 BGP_NOTIFY_UPDATE_ERR,
1353 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1354 return -1;
1355 }
1356
Paul Jakmafb982c22007-05-04 20:15:47 +00001357 (bgp_attr_extra_get (attr))->cluster
1358 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001359
paul9985f832005-02-09 15:51:56 +00001360 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001361
1362 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1363
1364 return 0;
1365}
1366
1367/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001368int
paul718e3742002-12-13 20:15:29 +00001369bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1370 struct bgp_nlri *mp_update)
1371{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001372 afi_t afi;
1373 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001374 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001375 size_t start;
paul718e3742002-12-13 20:15:29 +00001376 int ret;
1377 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001378 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001379
1380 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001381 s = BGP_INPUT(peer);
1382 start = stream_get_getp(s);
1383
1384 /* safe to read statically sized header? */
1385#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001386#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001387 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001388 {
1389 zlog_info ("%s: %s sent invalid length, %lu",
1390 __func__, peer->host, (unsigned long)length);
1391 return -1;
1392 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001393
paul718e3742002-12-13 20:15:29 +00001394 /* Load AFI, SAFI. */
1395 afi = stream_getw (s);
1396 safi = stream_getc (s);
1397
1398 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001399 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001400
Paul Jakma03292802008-06-07 20:37:10 +00001401 if (LEN_LEFT < attre->mp_nexthop_len)
1402 {
1403 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1404 __func__, peer->host, attre->mp_nexthop_len);
1405 return -1;
1406 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001407
paul718e3742002-12-13 20:15:29 +00001408 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001409 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001410 {
1411 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001412 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001413 /* Probably needed for RFC 2283 */
1414 if (attr->nexthop.s_addr == 0)
1415 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001416 break;
1417 case 12:
1418 {
1419 u_int32_t rd_high;
1420 u_int32_t rd_low;
1421
1422 rd_high = stream_getl (s);
1423 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001424 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001425 }
1426 break;
1427#ifdef HAVE_IPV6
1428 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001429 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001430 break;
1431 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001432 stream_get (&attre->mp_nexthop_global, s, 16);
1433 stream_get (&attre->mp_nexthop_local, s, 16);
1434 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001435 {
1436 char buf1[INET6_ADDRSTRLEN];
1437 char buf2[INET6_ADDRSTRLEN];
1438
1439 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001440 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 +00001441 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001442 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001443 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001444 buf2, INET6_ADDRSTRLEN));
1445
Paul Jakmafb982c22007-05-04 20:15:47 +00001446 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001447 }
1448 break;
1449#endif /* HAVE_IPV6 */
1450 default:
Paul Jakma03292802008-06-07 20:37:10 +00001451 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1452 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001453 return -1;
paul718e3742002-12-13 20:15:29 +00001454 }
1455
Paul Jakma03292802008-06-07 20:37:10 +00001456 if (!LEN_LEFT)
1457 {
1458 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1459 __func__, peer->host);
1460 return -1;
1461 }
paul718e3742002-12-13 20:15:29 +00001462
Paul Jakma6e4ab122007-04-10 19:36:48 +00001463 {
1464 u_char val;
1465 if ((val = stream_getc (s)))
1466 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1467 peer->host, val);
1468 }
1469
1470 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001471 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001472 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001473 {
1474 zlog_info ("%s: (%s) Failed to read NLRI",
1475 __func__, peer->host);
1476 return -1;
1477 }
paul718e3742002-12-13 20:15:29 +00001478
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001479 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001480 {
1481 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001482 if (ret < 0)
1483 {
1484 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1485 __func__, peer->host);
1486 return -1;
1487 }
paul718e3742002-12-13 20:15:29 +00001488 }
1489
1490 mp_update->afi = afi;
1491 mp_update->safi = safi;
1492 mp_update->nlri = stream_pnt (s);
1493 mp_update->length = nlri_len;
1494
paul9985f832005-02-09 15:51:56 +00001495 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001496
1497 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001498#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001499}
1500
1501/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001502int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001503bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001504 struct bgp_nlri *mp_withdraw)
1505{
1506 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001507 afi_t afi;
1508 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001509 u_int16_t withdraw_len;
1510 int ret;
1511
1512 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001513
1514#define BGP_MP_UNREACH_MIN_SIZE 3
1515 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1516 return -1;
1517
paul718e3742002-12-13 20:15:29 +00001518 afi = stream_getw (s);
1519 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001520
1521 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001522
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001523 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001524 {
1525 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1526 if (ret < 0)
1527 return -1;
1528 }
1529
1530 mp_withdraw->afi = afi;
1531 mp_withdraw->safi = safi;
1532 mp_withdraw->nlri = stream_pnt (s);
1533 mp_withdraw->length = withdraw_len;
1534
paul9985f832005-02-09 15:51:56 +00001535 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001536
1537 return 0;
1538}
1539
1540/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001541static int
paul718e3742002-12-13 20:15:29 +00001542bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1543 struct attr *attr, u_char flag)
1544{
1545 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001546 {
1547 if (attr->extra)
1548 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001549 /* Empty extcomm doesn't seem to be invalid per se */
1550 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001551 }
Paul Jakmafc097162010-12-05 17:17:26 +00001552
1553 (bgp_attr_extra_get (attr))->ecommunity =
1554 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1555 /* XXX: fix ecommunity_parse to use stream API */
1556 stream_forward_getp (peer->ibuf, length);
1557
1558 if (!attr->extra->ecommunity)
1559 return -1;
1560
paul718e3742002-12-13 20:15:29 +00001561 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1562
1563 return 0;
1564}
1565
1566/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001567static int
paul718e3742002-12-13 20:15:29 +00001568bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1569 u_char type, bgp_size_t length, u_char *startp)
1570{
1571 bgp_size_t total;
1572 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001573 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001574
hassof4184462005-02-01 20:13:16 +00001575 if (BGP_DEBUG (normal, NORMAL))
1576 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1577 peer->host, type, length);
1578
paul718e3742002-12-13 20:15:29 +00001579 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001580 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001581 "Unknown attribute type %d length %d is received", type, length);
1582
1583 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001584 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001585
1586 /* Adjest total length to include type and length. */
1587 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1588
1589 /* If any of the mandatory well-known attributes are not recognized,
1590 then the Error Subcode is set to Unrecognized Well-known
1591 Attribute. The Data field contains the unrecognized attribute
1592 (type, length and value). */
1593 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1594 {
1595 /* Adjust startp to do not include flag value. */
1596 bgp_notify_send_with_data (peer,
1597 BGP_NOTIFY_UPDATE_ERR,
1598 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1599 startp, total);
1600 return -1;
1601 }
1602
1603 /* Unrecognized non-transitive optional attributes must be quietly
1604 ignored and not passed along to other BGP peers. */
1605 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1606 return 0;
1607
1608 /* If a path with recognized transitive optional attribute is
1609 accepted and passed along to other BGP peers and the Partial bit
1610 in the Attribute Flags octet is set to 1 by some previous AS, it
1611 is not set back to 0 by the current AS. */
1612 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1613
1614 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001615 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001616 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001617
Paul Jakmafb982c22007-05-04 20:15:47 +00001618 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001619
1620 if (transit->val)
1621 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1622 transit->length + total);
1623 else
1624 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1625
1626 memcpy (transit->val + transit->length, startp, total);
1627 transit->length += total;
1628
1629 return 0;
1630}
1631
1632/* Read attribute of update packet. This function is called from
1633 bgp_update() in bgpd.c. */
1634int
1635bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1636 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1637{
1638 int ret;
1639 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001640 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001641 bgp_size_t length;
1642 u_char *startp, *endp;
1643 u_char *attr_endp;
1644 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001645 /* we need the as4_path only until we have synthesized the as_path with it */
1646 /* same goes for as4_aggregator */
1647 struct aspath *as4_path = NULL;
1648 as_t as4_aggregator = 0;
1649 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001650
1651 /* Initialize bitmap. */
1652 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1653
1654 /* End pointer of BGP attribute. */
1655 endp = BGP_INPUT_PNT (peer) + size;
1656
1657 /* Get attributes to the end of attribute length. */
1658 while (BGP_INPUT_PNT (peer) < endp)
1659 {
1660 /* Check remaining length check.*/
1661 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1662 {
gdtc29fdba2004-12-09 14:46:46 +00001663 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001664 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001665 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001666 peer->host,
1667 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001668
1669 bgp_notify_send (peer,
1670 BGP_NOTIFY_UPDATE_ERR,
1671 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1672 return -1;
1673 }
1674
1675 /* Fetch attribute flag and type. */
1676 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001677 /* "The lower-order four bits of the Attribute Flags octet are
1678 unused. They MUST be zero when sent and MUST be ignored when
1679 received." */
1680 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001681 type = stream_getc (BGP_INPUT (peer));
1682
Paul Jakma370b64a2007-12-22 16:49:52 +00001683 /* Check whether Extended-Length applies and is in bounds */
1684 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1685 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1686 {
1687 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001688 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001689 peer->host,
1690 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1691
1692 bgp_notify_send (peer,
1693 BGP_NOTIFY_UPDATE_ERR,
1694 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1695 return -1;
1696 }
1697
paul718e3742002-12-13 20:15:29 +00001698 /* Check extended attribue length bit. */
1699 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1700 length = stream_getw (BGP_INPUT (peer));
1701 else
1702 length = stream_getc (BGP_INPUT (peer));
1703
1704 /* If any attribute appears more than once in the UPDATE
1705 message, then the Error Subcode is set to Malformed Attribute
1706 List. */
1707
1708 if (CHECK_BITMAP (seen, type))
1709 {
1710 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001711 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001712 peer->host, type);
1713
1714 bgp_notify_send (peer,
1715 BGP_NOTIFY_UPDATE_ERR,
1716 BGP_NOTIFY_UPDATE_MAL_ATTR);
1717 return -1;
1718 }
1719
1720 /* Set type to bitmap to check duplicate attribute. `type' is
1721 unsigned char so it never overflow bitmap range. */
1722
1723 SET_BITMAP (seen, type);
1724
1725 /* Overflow check. */
1726 attr_endp = BGP_INPUT_PNT (peer) + length;
1727
1728 if (attr_endp > endp)
1729 {
1730 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001731 "%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 +00001732 bgp_notify_send (peer,
1733 BGP_NOTIFY_UPDATE_ERR,
1734 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1735 return -1;
1736 }
1737
1738 /* OK check attribute and store it's value. */
1739 switch (type)
1740 {
1741 case BGP_ATTR_ORIGIN:
1742 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1743 break;
1744 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001745 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1746 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001747 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001748 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001749 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1750 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001751 break;
paul718e3742002-12-13 20:15:29 +00001752 case BGP_ATTR_NEXT_HOP:
1753 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1754 break;
1755 case BGP_ATTR_MULTI_EXIT_DISC:
1756 ret = bgp_attr_med (peer, length, attr, flag, startp);
1757 break;
1758 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001759 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001760 break;
1761 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001762 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001763 break;
1764 case BGP_ATTR_AGGREGATOR:
1765 ret = bgp_attr_aggregator (peer, length, attr, flag);
1766 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001767 case BGP_ATTR_AS4_AGGREGATOR:
1768 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1769 break;
paul718e3742002-12-13 20:15:29 +00001770 case BGP_ATTR_COMMUNITIES:
1771 ret = bgp_attr_community (peer, length, attr, flag);
1772 break;
1773 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienko5de17192011-09-30 15:08:54 +04001774 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001775 break;
1776 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001777 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001778 break;
1779 case BGP_ATTR_MP_REACH_NLRI:
1780 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1781 break;
1782 case BGP_ATTR_MP_UNREACH_NLRI:
1783 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1784 break;
1785 case BGP_ATTR_EXT_COMMUNITIES:
1786 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1787 break;
1788 default:
1789 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1790 break;
1791 }
1792
1793 /* If error occured immediately return to the caller. */
1794 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001795 {
1796 zlog (peer->log, LOG_WARNING,
1797 "%s: Attribute %s, parse error",
1798 peer->host,
1799 LOOKUP (attr_str, type));
1800 bgp_notify_send (peer,
1801 BGP_NOTIFY_UPDATE_ERR,
1802 BGP_NOTIFY_UPDATE_MAL_ATTR);
1803 return ret;
1804 }
paul718e3742002-12-13 20:15:29 +00001805
1806 /* Check the fetched length. */
1807 if (BGP_INPUT_PNT (peer) != attr_endp)
1808 {
1809 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001810 "%s: BGP attribute %s, fetch error",
1811 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001812 bgp_notify_send (peer,
1813 BGP_NOTIFY_UPDATE_ERR,
1814 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1815 return -1;
1816 }
1817 }
1818
1819 /* Check final read pointer is same as end pointer. */
1820 if (BGP_INPUT_PNT (peer) != endp)
1821 {
1822 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001823 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001824 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001825 bgp_notify_send (peer,
1826 BGP_NOTIFY_UPDATE_ERR,
1827 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1828 return -1;
1829 }
1830
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001831 /*
1832 * At this place we can see whether we got AS4_PATH and/or
1833 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1834 * We can not do this before we've read all attributes because
1835 * the as4 handling does not say whether AS4_PATH has to be sent
1836 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1837 * in relationship to AGGREGATOR.
1838 * So, to be defensive, we are not relying on any order and read
1839 * all attributes first, including these 32bit ones, and now,
1840 * afterwards, we look what and if something is to be done for as4.
1841 */
1842 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1843 as4_aggregator, &as4_aggregator_addr))
1844 return -1;
1845
1846 /* At this stage, we have done all fiddling with as4, and the
1847 * resulting info is in attr->aggregator resp. attr->aspath
1848 * so we can chuck as4_aggregator and as4_path alltogether in
1849 * order to save memory
1850 */
1851 if ( as4_path )
1852 {
1853 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1854 as4_path = NULL;
1855 /* The flag that we got this is still there, but that does not
1856 * do any trouble
1857 */
1858 }
1859 /*
1860 * The "rest" of the code does nothing with as4_aggregator.
1861 * there is no memory attached specifically which is not part
1862 * of the attr.
1863 * so ignoring just means do nothing.
1864 */
1865 /*
1866 * Finally do the checks on the aspath we did not do yet
1867 * because we waited for a potentially synthesized aspath.
1868 */
1869 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1870 {
1871 ret = bgp_attr_aspath_check( peer, attr );
1872 if ( ret < 0 )
1873 return ret;
1874 }
1875
paul718e3742002-12-13 20:15:29 +00001876 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001877 if (attr->extra && attr->extra->transit)
1878 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001879
1880 return 0;
1881}
1882
1883/* Well-known attribute check. */
1884int
1885bgp_attr_check (struct peer *peer, struct attr *attr)
1886{
1887 u_char type = 0;
1888
1889 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1890 type = BGP_ATTR_ORIGIN;
1891
1892 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1893 type = BGP_ATTR_AS_PATH;
1894
1895 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1896 type = BGP_ATTR_NEXT_HOP;
1897
1898 if (peer_sort (peer) == BGP_PEER_IBGP
1899 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1900 type = BGP_ATTR_LOCAL_PREF;
1901
1902 if (type)
1903 {
1904 zlog (peer->log, LOG_WARNING,
1905 "%s Missing well-known attribute %d.",
1906 peer->host, type);
1907 bgp_notify_send_with_data (peer,
1908 BGP_NOTIFY_UPDATE_ERR,
1909 BGP_NOTIFY_UPDATE_MISS_ATTR,
1910 &type, 1);
1911 return -1;
1912 }
1913 return 0;
1914}
1915
1916int stream_put_prefix (struct stream *, struct prefix *);
1917
1918/* Make attribute packet. */
1919bgp_size_t
1920bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1921 struct stream *s, struct attr *attr, struct prefix *p,
1922 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001923 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001924{
paulfe69a502005-09-10 16:55:02 +00001925 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001926 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001927 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001928 int send_as4_path = 0;
1929 int send_as4_aggregator = 0;
1930 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001931
1932 if (! bgp)
1933 bgp = bgp_get_default ();
1934
1935 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001936 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001937
1938 /* Origin attribute. */
1939 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1940 stream_putc (s, BGP_ATTR_ORIGIN);
1941 stream_putc (s, 1);
1942 stream_putc (s, attr->origin);
1943
1944 /* AS path attribute. */
1945
1946 /* If remote-peer is EBGP */
1947 if (peer_sort (peer) == BGP_PEER_EBGP
1948 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001949 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001950 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001951 {
1952 aspath = aspath_dup (attr->aspath);
1953
1954 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1955 {
1956 /* Strip the confed info, and then stuff our path CONFED_ID
1957 on the front */
1958 aspath = aspath_delete_confed_seq (aspath);
1959 aspath = aspath_add_seq (aspath, bgp->confed_id);
1960 }
1961 else
1962 {
1963 aspath = aspath_add_seq (aspath, peer->local_as);
1964 if (peer->change_local_as)
1965 aspath = aspath_add_seq (aspath, peer->change_local_as);
1966 }
1967 }
1968 else if (peer_sort (peer) == BGP_PEER_CONFED)
1969 {
1970 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1971 aspath = aspath_dup (attr->aspath);
1972 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1973 }
1974 else
1975 aspath = attr->aspath;
1976
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001977 /* If peer is not AS4 capable, then:
1978 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1979 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1980 * types are in it (i.e. exclude them if they are there)
1981 * AND do this only if there is at least one asnum > 65535 in the path!
1982 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1983 * all ASnums > 65535 to BGP_AS_TRANS
1984 */
paul718e3742002-12-13 20:15:29 +00001985
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001986 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1987 stream_putc (s, BGP_ATTR_AS_PATH);
1988 aspath_sizep = stream_get_endp (s);
1989 stream_putw (s, 0);
1990 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1991
1992 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1993 * in the path
1994 */
1995 if (!use32bit && aspath_has_as4 (aspath))
1996 send_as4_path = 1; /* we'll do this later, at the correct place */
1997
paul718e3742002-12-13 20:15:29 +00001998 /* Nexthop attribute. */
1999 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2000 {
2001 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2002 stream_putc (s, BGP_ATTR_NEXT_HOP);
2003 stream_putc (s, 4);
2004 if (safi == SAFI_MPLS_VPN)
2005 {
2006 if (attr->nexthop.s_addr == 0)
2007 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2008 else
2009 stream_put_ipv4 (s, attr->nexthop.s_addr);
2010 }
2011 else
2012 stream_put_ipv4 (s, attr->nexthop.s_addr);
2013 }
2014
2015 /* MED attribute. */
2016 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2017 {
2018 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2019 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2020 stream_putc (s, 4);
2021 stream_putl (s, attr->med);
2022 }
2023
2024 /* Local preference. */
2025 if (peer_sort (peer) == BGP_PEER_IBGP ||
2026 peer_sort (peer) == BGP_PEER_CONFED)
2027 {
2028 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2029 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2030 stream_putc (s, 4);
2031 stream_putl (s, attr->local_pref);
2032 }
2033
2034 /* Atomic aggregate. */
2035 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2036 {
2037 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2038 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2039 stream_putc (s, 0);
2040 }
2041
2042 /* Aggregator. */
2043 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2044 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002045 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002046
2047 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002048 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2049 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002050
2051 if (use32bit)
2052 {
2053 /* AS4 capable peer */
2054 stream_putc (s, 8);
2055 stream_putl (s, attr->extra->aggregator_as);
2056 }
2057 else
2058 {
2059 /* 2-byte AS peer */
2060 stream_putc (s, 6);
2061
2062 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2063 if ( attr->extra->aggregator_as > 65535 )
2064 {
2065 stream_putw (s, BGP_AS_TRANS);
2066
2067 /* we have to send AS4_AGGREGATOR, too.
2068 * we'll do that later in order to send attributes in ascending
2069 * order.
2070 */
2071 send_as4_aggregator = 1;
2072 }
2073 else
2074 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2075 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002076 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002077 }
2078
2079 /* Community attribute. */
2080 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2081 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2082 {
2083 if (attr->community->size * 4 > 255)
2084 {
2085 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2086 stream_putc (s, BGP_ATTR_COMMUNITIES);
2087 stream_putw (s, attr->community->size * 4);
2088 }
2089 else
2090 {
2091 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2092 stream_putc (s, BGP_ATTR_COMMUNITIES);
2093 stream_putc (s, attr->community->size * 4);
2094 }
2095 stream_put (s, attr->community->val, attr->community->size * 4);
2096 }
2097
2098 /* Route Reflector. */
2099 if (peer_sort (peer) == BGP_PEER_IBGP
2100 && from
2101 && peer_sort (from) == BGP_PEER_IBGP)
2102 {
2103 /* Originator ID. */
2104 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2105 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2106 stream_putc (s, 4);
2107
2108 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002109 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002110 else
2111 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002112
2113 /* Cluster list. */
2114 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2115 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2116
Paul Jakma9eda90c2007-08-30 13:36:17 +00002117 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002118 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002119 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002120 /* If this peer configuration's parent BGP has cluster_id. */
2121 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2122 stream_put_in_addr (s, &bgp->cluster_id);
2123 else
2124 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002125 stream_put (s, attr->extra->cluster->list,
2126 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002127 }
2128 else
2129 {
2130 stream_putc (s, 4);
2131 /* If this peer configuration's parent BGP has cluster_id. */
2132 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2133 stream_put_in_addr (s, &bgp->cluster_id);
2134 else
2135 stream_put_in_addr (s, &bgp->router_id);
2136 }
2137 }
2138
2139#ifdef HAVE_IPV6
2140 /* If p is IPv6 address put it into attribute. */
2141 if (p->family == AF_INET6)
2142 {
2143 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002144 struct attr_extra *attre = attr->extra;
2145
2146 assert (attr->extra);
2147
paul718e3742002-12-13 20:15:29 +00002148 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2149 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002150 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002151 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002152 stream_putw (s, AFI_IP6); /* AFI */
2153 stream_putc (s, safi); /* SAFI */
2154
Paul Jakmafb982c22007-05-04 20:15:47 +00002155 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002156
Paul Jakmafb982c22007-05-04 20:15:47 +00002157 if (attre->mp_nexthop_len == 16)
2158 stream_put (s, &attre->mp_nexthop_global, 16);
2159 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002160 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002161 stream_put (s, &attre->mp_nexthop_global, 16);
2162 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002163 }
2164
2165 /* SNPA */
2166 stream_putc (s, 0);
2167
paul718e3742002-12-13 20:15:29 +00002168 /* Prefix write. */
2169 stream_put_prefix (s, p);
2170
2171 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002172 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002173 }
2174#endif /* HAVE_IPV6 */
2175
2176 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2177 {
2178 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002179
2180 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2181 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002182 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002183 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002184 stream_putw (s, AFI_IP); /* AFI */
2185 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2186
2187 stream_putc (s, 4);
2188 stream_put_ipv4 (s, attr->nexthop.s_addr);
2189
2190 /* SNPA */
2191 stream_putc (s, 0);
2192
paul718e3742002-12-13 20:15:29 +00002193 /* Prefix write. */
2194 stream_put_prefix (s, p);
2195
2196 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002197 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002198 }
2199
2200 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2201 {
2202 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002203
2204 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2205 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002206 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002207 stream_putc (s, 0); /* Length of this attribute. */
2208 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002209 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002210
2211 stream_putc (s, 12);
2212 stream_putl (s, 0);
2213 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002214 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002215
2216 /* SNPA */
2217 stream_putc (s, 0);
2218
paul718e3742002-12-13 20:15:29 +00002219 /* Tag, RD, Prefix write. */
2220 stream_putc (s, p->prefixlen + 88);
2221 stream_put (s, tag, 3);
2222 stream_put (s, prd->val, 8);
2223 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2224
2225 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002226 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002227 }
2228
2229 /* Extended Communities attribute. */
2230 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2231 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2232 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002233 struct attr_extra *attre = attr->extra;
2234
2235 assert (attre);
2236
2237 if (peer_sort (peer) == BGP_PEER_IBGP
2238 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002239 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002240 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002241 {
2242 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2243 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002244 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002245 }
2246 else
2247 {
2248 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2249 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002250 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002251 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002252 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002253 }
2254 else
2255 {
paul5228ad22004-06-04 17:58:18 +00002256 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002257 int tbit;
2258 int ecom_tr_size = 0;
2259 int i;
2260
Paul Jakmafb982c22007-05-04 20:15:47 +00002261 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002262 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002263 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002264 tbit = *pnt;
2265
2266 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2267 continue;
2268
2269 ecom_tr_size++;
2270 }
2271
2272 if (ecom_tr_size)
2273 {
2274 if (ecom_tr_size * 8 > 255)
2275 {
2276 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2277 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2278 stream_putw (s, ecom_tr_size * 8);
2279 }
2280 else
2281 {
2282 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2283 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2284 stream_putc (s, ecom_tr_size * 8);
2285 }
2286
Paul Jakmafb982c22007-05-04 20:15:47 +00002287 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002288 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002289 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002290 tbit = *pnt;
2291
2292 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2293 continue;
2294
2295 stream_put (s, pnt, 8);
2296 }
2297 }
paul718e3742002-12-13 20:15:29 +00002298 }
paul718e3742002-12-13 20:15:29 +00002299 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002300
2301 if ( send_as4_path )
2302 {
2303 /* If the peer is NOT As4 capable, AND */
2304 /* there are ASnums > 65535 in path THEN
2305 * give out AS4_PATH */
2306
2307 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2308 * path segments!
2309 * Hm, I wonder... confederation things *should* only be at
2310 * the beginning of an aspath, right? Then we should use
2311 * aspath_delete_confed_seq for this, because it is already
2312 * there! (JK)
2313 * Folks, talk to me: what is reasonable here!?
2314 */
2315 aspath = aspath_delete_confed_seq (aspath);
2316
2317 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2318 stream_putc (s, BGP_ATTR_AS4_PATH);
2319 aspath_sizep = stream_get_endp (s);
2320 stream_putw (s, 0);
2321 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2322 }
2323
2324 if (aspath != attr->aspath)
2325 aspath_free (aspath);
2326
2327 if ( send_as4_aggregator )
2328 {
2329 assert (attr->extra);
2330
2331 /* send AS4_AGGREGATOR, at this place */
2332 /* this section of code moved here in order to ensure the correct
2333 * *ascending* order of attributes
2334 */
2335 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2336 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2337 stream_putc (s, 8);
2338 stream_putl (s, attr->extra->aggregator_as);
2339 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2340 }
Paul Jakma41367172007-08-06 15:24:51 +00002341
paul718e3742002-12-13 20:15:29 +00002342 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002343 if (attr->extra && attr->extra->transit)
2344 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002345
2346 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002347 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002348}
2349
2350bgp_size_t
2351bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2352 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002353 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002354{
2355 unsigned long cp;
2356 unsigned long attrlen_pnt;
2357 bgp_size_t size;
2358
paul9985f832005-02-09 15:51:56 +00002359 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002360
2361 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2362 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2363
paul9985f832005-02-09 15:51:56 +00002364 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002365 stream_putc (s, 0); /* Length of this attribute. */
2366
2367 stream_putw (s, family2afi (p->family));
2368
2369 if (safi == SAFI_MPLS_VPN)
2370 {
2371 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002372 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002373
2374 /* prefix. */
2375 stream_putc (s, p->prefixlen + 88);
2376 stream_put (s, tag, 3);
2377 stream_put (s, prd->val, 8);
2378 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2379 }
2380 else
2381 {
2382 /* SAFI */
2383 stream_putc (s, safi);
2384
2385 /* prefix */
2386 stream_put_prefix (s, p);
2387 }
2388
2389 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002390 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002391 stream_putc_at (s, attrlen_pnt, size);
2392
paul9985f832005-02-09 15:51:56 +00002393 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002394}
2395
2396/* Initialization of attribute. */
2397void
paulfe69a502005-09-10 16:55:02 +00002398bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002399{
paul718e3742002-12-13 20:15:29 +00002400 aspath_init ();
2401 attrhash_init ();
2402 community_init ();
2403 ecommunity_init ();
2404 cluster_init ();
2405 transit_init ();
2406}
2407
Chris Caputo228da422009-07-18 05:44:03 +00002408void
2409bgp_attr_finish (void)
2410{
2411 aspath_finish ();
2412 attrhash_finish ();
2413 community_finish ();
2414 ecommunity_finish ();
2415 cluster_finish ();
2416 transit_finish ();
2417}
2418
paul718e3742002-12-13 20:15:29 +00002419/* Make attribute packet. */
2420void
paula3845922003-10-18 01:30:50 +00002421bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2422 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002423{
2424 unsigned long cp;
2425 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002426 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002427 struct aspath *aspath;
2428
2429 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002430 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002431
2432 /* Place holder of length. */
2433 stream_putw (s, 0);
2434
2435 /* Origin attribute. */
2436 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2437 stream_putc (s, BGP_ATTR_ORIGIN);
2438 stream_putc (s, 1);
2439 stream_putc (s, attr->origin);
2440
2441 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002442
2443 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2444 stream_putc (s, BGP_ATTR_AS_PATH);
2445 aspath_lenp = stream_get_endp (s);
2446 stream_putw (s, 0);
2447
2448 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002449
2450 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002451 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2452 if(prefix != NULL
2453#ifdef HAVE_IPV6
2454 && prefix->family != AF_INET6
2455#endif /* HAVE_IPV6 */
2456 )
2457 {
2458 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2459 stream_putc (s, BGP_ATTR_NEXT_HOP);
2460 stream_putc (s, 4);
2461 stream_put_ipv4 (s, attr->nexthop.s_addr);
2462 }
paul718e3742002-12-13 20:15:29 +00002463
2464 /* MED attribute. */
2465 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2466 {
2467 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2468 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2469 stream_putc (s, 4);
2470 stream_putl (s, attr->med);
2471 }
2472
2473 /* Local preference. */
2474 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2475 {
2476 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2477 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2478 stream_putc (s, 4);
2479 stream_putl (s, attr->local_pref);
2480 }
2481
2482 /* Atomic aggregate. */
2483 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2484 {
2485 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2486 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2487 stream_putc (s, 0);
2488 }
2489
2490 /* Aggregator. */
2491 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2492 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002493 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002494 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2495 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002496 stream_putc (s, 8);
2497 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002498 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002499 }
2500
2501 /* Community attribute. */
2502 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2503 {
2504 if (attr->community->size * 4 > 255)
2505 {
2506 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2507 stream_putc (s, BGP_ATTR_COMMUNITIES);
2508 stream_putw (s, attr->community->size * 4);
2509 }
2510 else
2511 {
2512 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2513 stream_putc (s, BGP_ATTR_COMMUNITIES);
2514 stream_putc (s, attr->community->size * 4);
2515 }
2516 stream_put (s, attr->community->val, attr->community->size * 4);
2517 }
2518
paula3845922003-10-18 01:30:50 +00002519#ifdef HAVE_IPV6
2520 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002521 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2522 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002523 {
2524 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002525 struct attr_extra *attre = attr->extra;
2526
paula3845922003-10-18 01:30:50 +00002527 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2528 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002529 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002530
2531 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002532 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002533 stream_putw(s, AFI_IP6); /* AFI */
2534 stream_putc(s, SAFI_UNICAST); /* SAFI */
2535
2536 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002537 stream_putc(s, attre->mp_nexthop_len);
2538 stream_put(s, &attre->mp_nexthop_global, 16);
2539 if (attre->mp_nexthop_len == 32)
2540 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002541
2542 /* SNPA */
2543 stream_putc(s, 0);
2544
2545 /* Prefix */
2546 stream_put_prefix(s, prefix);
2547
2548 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002549 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002550 }
2551#endif /* HAVE_IPV6 */
2552
paul718e3742002-12-13 20:15:29 +00002553 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002554 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002555 stream_putw_at (s, cp, len);
2556}