blob: 3f4b3ce4a6c00a90cfb7c45d3695d5018586f6fe [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070042static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000059 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
60 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
61 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
62 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000063};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070064static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
Stephen Hemminger9bddac42009-05-15 09:59:51 -070066static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000067
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 struct cluster_list *cluster;
73
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
76
77 if (cluster->length)
78 {
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
81 }
82 else
83 cluster->list = NULL;
84
85 cluster->refcnt = 0;
86
87 return cluster;
88}
89
90/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
103}
104
105int
106cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
107{
108 int i;
109
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
114}
115
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
123
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
126
127 while (length)
128 key += pnt[--length];
129
130 return key;
131}
132
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
Chris Caputo228da422009-07-18 05:44:03 +0000151#if 0
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
Stephen Hemminger393deb92008-08-18 14:13:29 -0700157 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
Chris Caputo228da422009-07-18 05:44:03 +0000170#endif
paul718e3742002-12-13 20:15:29 +0000171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
246 struct transit *ret;
247
248 if (transit->refcnt)
249 transit->refcnt--;
250
251 if (transit->refcnt == 0)
252 {
253 ret = hash_release (transit_hash, transit);
254 transit_free (transit);
255 }
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000259transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma923de652007-04-29 18:25:17 +0000261 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000262 unsigned int key = 0;
263 int length;
264 caddr_t pnt;
265
266 length = transit->length;
267 pnt = (caddr_t) transit->val;
268
269 while (length)
270 key += pnt[--length];
271
272 return key;
273}
274
paul94f2b392005-06-28 12:44:16 +0000275static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100276transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000277{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100278 const struct transit * transit1 = p1;
279 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000280
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100281 return (transit1->length == transit2->length &&
282 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000283}
284
paul94f2b392005-06-28 12:44:16 +0000285static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800286transit_init (void)
paul718e3742002-12-13 20:15:29 +0000287{
288 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
289}
Chris Caputo228da422009-07-18 05:44:03 +0000290
291static void
292transit_finish (void)
293{
294 hash_free (transit_hash);
295 transit_hash = NULL;
296}
paul718e3742002-12-13 20:15:29 +0000297
298/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700299static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000300
Paul Jakmafb982c22007-05-04 20:15:47 +0000301static struct attr_extra *
302bgp_attr_extra_new (void)
303{
304 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
305}
306
307void
308bgp_attr_extra_free (struct attr *attr)
309{
310 if (attr->extra)
311 {
312 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
313 attr->extra = NULL;
314 }
315}
316
317struct attr_extra *
318bgp_attr_extra_get (struct attr *attr)
319{
320 if (!attr->extra)
321 attr->extra = bgp_attr_extra_new();
322 return attr->extra;
323}
324
325/* Shallow copy of an attribute
326 * Though, not so shallow that it doesn't copy the contents
327 * of the attr_extra pointed to by 'extra'
328 */
329void
330bgp_attr_dup (struct attr *new, struct attr *orig)
331{
332 *new = *orig;
333 if (orig->extra)
334 {
335 new->extra = bgp_attr_extra_new();
336 *new->extra = *orig->extra;
337 }
338}
339
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000340unsigned long int
341attr_count (void)
342{
343 return attrhash->count;
344}
345
346unsigned long int
347attr_unknown_count (void)
348{
349 return transit_hash->count;
350}
351
paul718e3742002-12-13 20:15:29 +0000352unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000353attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000354{
Paul Jakma923de652007-04-29 18:25:17 +0000355 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000356 unsigned int key = 0;
357
358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000362
363 if (attr->extra)
364 {
365 key += attr->extra->aggregator_as;
366 key += attr->extra->aggregator_addr.s_addr;
367 key += attr->extra->weight;
368 key += attr->extra->mp_nexthop_global_in.s_addr;
369 }
370
paul718e3742002-12-13 20:15:29 +0000371 if (attr->aspath)
372 key += aspath_key_make (attr->aspath);
373 if (attr->community)
374 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000375
376 if (attr->extra)
377 {
378 if (attr->extra->ecommunity)
379 key += ecommunity_hash_make (attr->extra->ecommunity);
380 if (attr->extra->cluster)
381 key += cluster_hash_key_make (attr->extra->cluster);
382 if (attr->extra->transit)
383 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000384
385#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 {
387 int i;
388
389 key += attr->extra->mp_nexthop_len;
390 for (i = 0; i < 16; i++)
391 key += attr->extra->mp_nexthop_global.s6_addr[i];
392 for (i = 0; i < 16; i++)
393 key += attr->extra->mp_nexthop_local.s6_addr[i];
394 }
paul718e3742002-12-13 20:15:29 +0000395#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000396 }
paul718e3742002-12-13 20:15:29 +0000397
398 return key;
399}
400
401int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100402attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000403{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100404 const struct attr * attr1 = p1;
405 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000406
paul718e3742002-12-13 20:15:29 +0000407 if (attr1->flag == attr2->flag
408 && attr1->origin == attr2->origin
409 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000410 && attr1->aspath == attr2->aspath
411 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000412 && attr1->med == attr2->med
Paul Jakmae70e5752011-07-05 00:41:59 +0400413 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000414 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100415 const struct attr_extra *ae1 = attr1->extra;
416 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000417
418 if (ae1 && ae2
419 && ae1->aggregator_as == ae2->aggregator_as
420 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
421 && ae1->weight == ae2->weight
422#ifdef HAVE_IPV6
423 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
424 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
425 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
426#endif /* HAVE_IPV6 */
427 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
428 && ae1->ecommunity == ae2->ecommunity
429 && ae1->cluster == ae2->cluster
430 && ae1->transit == ae2->transit)
431 return 1;
432 else if (ae1 || ae2)
433 return 0;
434 /* neither attribute has extra attributes, so they're same */
435 return 1;
436 }
paul718e3742002-12-13 20:15:29 +0000437 else
438 return 0;
439}
440
paul94f2b392005-06-28 12:44:16 +0000441static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100442attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000443{
444 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
445}
446
paul94f2b392005-06-28 12:44:16 +0000447static void
Chris Caputo228da422009-07-18 05:44:03 +0000448attrhash_finish (void)
449{
450 hash_free (attrhash);
451 attrhash = NULL;
452}
453
454static void
paul718e3742002-12-13 20:15:29 +0000455attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
456{
457 struct attr *attr = backet->data;
458
459 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
460 inet_ntoa (attr->nexthop), VTY_NEWLINE);
461}
462
463void
464attr_show_all (struct vty *vty)
465{
466 hash_iterate (attrhash,
467 (void (*)(struct hash_backet *, void *))
468 attr_show_all_iterator,
469 vty);
470}
471
paul94f2b392005-06-28 12:44:16 +0000472static void *
Paul Jakma923de652007-04-29 18:25:17 +0000473bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000474{
Paul Jakma923de652007-04-29 18:25:17 +0000475 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000476 struct attr *attr;
477
478 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
479 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000480 if (val->extra)
481 {
482 attr->extra = bgp_attr_extra_new ();
483 *attr->extra = *val->extra;
484 }
paul718e3742002-12-13 20:15:29 +0000485 attr->refcnt = 0;
486 return attr;
487}
488
489/* Internet argument attribute. */
490struct attr *
491bgp_attr_intern (struct attr *attr)
492{
493 struct attr *find;
494
495 /* Intern referenced strucutre. */
496 if (attr->aspath)
497 {
498 if (! attr->aspath->refcnt)
499 attr->aspath = aspath_intern (attr->aspath);
500 else
501 attr->aspath->refcnt++;
502 }
503 if (attr->community)
504 {
505 if (! attr->community->refcnt)
506 attr->community = community_intern (attr->community);
507 else
508 attr->community->refcnt++;
509 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000510 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000511 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000512 struct attr_extra *attre = attr->extra;
513
514 if (attre->ecommunity)
515 {
516 if (! attre->ecommunity->refcnt)
517 attre->ecommunity = ecommunity_intern (attre->ecommunity);
518 else
519 attre->ecommunity->refcnt++;
520 }
521 if (attre->cluster)
522 {
523 if (! attre->cluster->refcnt)
524 attre->cluster = cluster_intern (attre->cluster);
525 else
526 attre->cluster->refcnt++;
527 }
528 if (attre->transit)
529 {
530 if (! attre->transit->refcnt)
531 attre->transit = transit_intern (attre->transit);
532 else
533 attre->transit->refcnt++;
534 }
paul718e3742002-12-13 20:15:29 +0000535 }
536
537 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
538 find->refcnt++;
539
540 return find;
541}
542
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544/* Make network statement's attribute. */
545struct attr *
546bgp_attr_default_set (struct attr *attr, u_char origin)
547{
548 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000549 bgp_attr_extra_get (attr);
550
paul718e3742002-12-13 20:15:29 +0000551 attr->origin = origin;
552 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
553 attr->aspath = aspath_empty ();
554 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000556 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
557#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000559#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000560
paul718e3742002-12-13 20:15:29 +0000561 return attr;
562}
563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564
paul718e3742002-12-13 20:15:29 +0000565/* Make network statement's attribute. */
566struct attr *
567bgp_attr_default_intern (u_char origin)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
572
573 memset (&attr, 0, sizeof (struct attr));
574 attre = bgp_attr_extra_get (&attr);
575
Paul Jakma03e214c2007-04-29 18:31:07 +0000576 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000577
578 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 bgp_attr_extra_free (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 aspath_unintern (new->aspath);
582 return new;
583}
584
585struct attr *
586bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
587 struct aspath *aspath,
588 struct community *community, int as_set)
589{
590 struct attr attr;
591 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000592 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000593
594 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000595 attre = bgp_attr_extra_get (&attr);
596
paul718e3742002-12-13 20:15:29 +0000597 /* Origin attribute. */
598 attr.origin = origin;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
600
601 /* AS path attribute. */
602 if (aspath)
603 attr.aspath = aspath_intern (aspath);
604 else
605 attr.aspath = aspath_empty ();
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
607
608 /* Next hop attribute. */
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
610
611 if (community)
612 {
613 attr.community = community;
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
615 }
616
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000618#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000619 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000620#endif
621 if (! as_set)
622 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
623 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
624 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000625 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000626 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 attre->aggregator_as = bgp->as;
628 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000629
630 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000631 bgp_attr_extra_free (&attr);
632
paul718e3742002-12-13 20:15:29 +0000633 aspath_unintern (new->aspath);
634 return new;
635}
636
637/* Free bgp attribute and aspath. */
638void
639bgp_attr_unintern (struct attr *attr)
640{
641 struct attr *ret;
642 struct aspath *aspath;
643 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000644 struct ecommunity *ecommunity = NULL;
645 struct cluster_list *cluster = NULL;
646 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000647
648 /* Decrement attribute reference. */
649 attr->refcnt--;
650 aspath = attr->aspath;
651 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000652 if (attr->extra)
653 {
654 ecommunity = attr->extra->ecommunity;
655 cluster = attr->extra->cluster;
656 transit = attr->extra->transit;
657 }
paul718e3742002-12-13 20:15:29 +0000658
659 /* If reference becomes zero then free attribute object. */
660 if (attr->refcnt == 0)
661 {
662 ret = hash_release (attrhash, attr);
663 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000664 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000665 XFREE (MTYPE_ATTR, attr);
666 }
667
668 /* aspath refcount shoud be decrement. */
669 if (aspath)
670 aspath_unintern (aspath);
671 if (community)
672 community_unintern (community);
673 if (ecommunity)
674 ecommunity_unintern (ecommunity);
675 if (cluster)
676 cluster_unintern (cluster);
677 if (transit)
678 transit_unintern (transit);
679}
680
681void
682bgp_attr_flush (struct attr *attr)
683{
684 if (attr->aspath && ! attr->aspath->refcnt)
685 aspath_free (attr->aspath);
686 if (attr->community && ! attr->community->refcnt)
687 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000688 if (attr->extra)
689 {
690 struct attr_extra *attre = attr->extra;
691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
692 ecommunity_free (attre->ecommunity);
693 if (attre->cluster && ! attre->cluster->refcnt)
694 cluster_free (attre->cluster);
695 if (attre->transit && ! attre->transit->refcnt)
696 transit_free (attre->transit);
697 }
paul718e3742002-12-13 20:15:29 +0000698}
699
700/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000701static int
paul718e3742002-12-13 20:15:29 +0000702bgp_attr_origin (struct peer *peer, bgp_size_t length,
703 struct attr *attr, u_char flag, u_char *startp)
704{
705 bgp_size_t total;
706
707 /* total is entire attribute length include Attribute Flags (1),
708 Attribute Type code (1) and Attribute length (1 or 2). */
709 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
710
711 /* If any recognized attribute has Attribute Flags that conflict
712 with the Attribute Type Code, then the Error Subcode is set to
713 Attribute Flags Error. The Data field contains the erroneous
714 attribute (type, length and value). */
715 if (flag != BGP_ATTR_FLAG_TRANS)
716 {
717 zlog (peer->log, LOG_ERR,
718 "Origin attribute flag isn't transitive %d", flag);
719 bgp_notify_send_with_data (peer,
720 BGP_NOTIFY_UPDATE_ERR,
721 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
722 startp, total);
723 return -1;
724 }
725
726 /* If any recognized attribute has Attribute Length that conflicts
727 with the expected length (based on the attribute type code), then
728 the Error Subcode is set to Attribute Length Error. The Data
729 field contains the erroneous attribute (type, length and
730 value). */
731 if (length != 1)
732 {
733 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
734 length);
735 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
736 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
737 startp, total);
738 return -1;
739 }
740
741 /* Fetch origin attribute. */
742 attr->origin = stream_getc (BGP_INPUT (peer));
743
744 /* If the ORIGIN attribute has an undefined value, then the Error
745 Subcode is set to Invalid Origin Attribute. The Data field
746 contains the unrecognized attribute (type, length and value). */
747 if ((attr->origin != BGP_ORIGIN_IGP)
748 && (attr->origin != BGP_ORIGIN_EGP)
749 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
750 {
751 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
752 attr->origin);
753
754 bgp_notify_send_with_data (peer,
755 BGP_NOTIFY_UPDATE_ERR,
756 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
757 startp, total);
758 return -1;
759 }
760
761 /* Set oring attribute flag. */
762 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
763
764 return 0;
765}
Chris Hallcddb8112010-08-09 22:31:37 +0400766/* Parse AS path information. This function is wrapper of aspath_parse.
767 *
768 * Parses AS_PATH or AS4_PATH.
769 *
770 * Returns: if valid: address of struct aspath in the hash of known aspaths,
771 * with reference count incremented.
772 * else: NULL
773 *
774 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
775 * have segments == NULL and str == zero length string (unique).
776 */
777static struct aspath *
paul718e3742002-12-13 20:15:29 +0000778bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400779 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000780{
Chris Hallcddb8112010-08-09 22:31:37 +0400781 u_char require ;
782 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000783
Chris Hallcddb8112010-08-09 22:31:37 +0400784 /* Check the attribute flags */
785 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
786 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000787
Chris Hallcddb8112010-08-09 22:31:37 +0400788 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000789 {
Chris Hallcddb8112010-08-09 22:31:37 +0400790 const char* path_type ;
791 bgp_size_t total;
792
793 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
794
795 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000796 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400797 "%s attribute flag isn't transitive %d", path_type, flag) ;
798
799 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
800 zlog (peer->log, LOG_ERR,
801 "%s attribute flag must %sbe optional %d", path_type,
802 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
803
804 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
805
paul718e3742002-12-13 20:15:29 +0000806 bgp_notify_send_with_data (peer,
807 BGP_NOTIFY_UPDATE_ERR,
808 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
809 startp, total);
paul718e3742002-12-13 20:15:29 +0000810
Chris Hallcddb8112010-08-09 22:31:37 +0400811 return NULL ;
812 } ;
813
814 /* Parse the AS_PATH/AS4_PATH body.
815 *
816 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
817 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000818 */
Chris Hallcddb8112010-08-09 22:31:37 +0400819 asp = aspath_parse (peer->ibuf, length,
820 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000821
Chris Hallcddb8112010-08-09 22:31:37 +0400822 if (asp != NULL)
823 {
824 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
825 : BGP_ATTR_AS_PATH) ;
826 }
827 else
paul718e3742002-12-13 20:15:29 +0000828 {
829 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400830
831 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000832 bgp_notify_send (peer,
833 BGP_NOTIFY_UPDATE_ERR,
834 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400835 } ;
paul718e3742002-12-13 20:15:29 +0000836
Chris Hallcddb8112010-08-09 22:31:37 +0400837 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000838}
839
840static int bgp_attr_aspath_check( struct peer *peer,
841 struct attr *attr)
842{
843 /* These checks were part of bgp_attr_aspath, but with
844 * as4 we should to check aspath things when
845 * aspath synthesizing with as4_path has already taken place.
846 * Otherwise we check ASPATH and use the synthesized thing, and that is
847 * not right.
848 * So do the checks later, i.e. here
849 */
850 struct bgp *bgp = peer->bgp;
851 struct aspath *aspath;
852
paul718e3742002-12-13 20:15:29 +0000853 bgp = peer->bgp;
854
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300855 /* Confederation sanity check. */
856 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
857 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
858 {
859 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
860 bgp_notify_send (peer,
861 BGP_NOTIFY_UPDATE_ERR,
862 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
863 return -1;
864 }
865
paul718e3742002-12-13 20:15:29 +0000866 /* First AS check for EBGP. */
867 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
868 {
869 if (peer_sort (peer) == BGP_PEER_EBGP
870 && ! aspath_firstas_check (attr->aspath, peer->as))
871 {
872 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400873 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000874 bgp_notify_send (peer,
875 BGP_NOTIFY_UPDATE_ERR,
876 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
877 return -1;
878 }
879 }
880
881 /* local-as prepend */
882 if (peer->change_local_as &&
883 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
884 {
885 aspath = aspath_dup (attr->aspath);
886 aspath = aspath_add_seq (aspath, peer->change_local_as);
887 aspath_unintern (attr->aspath);
888 attr->aspath = aspath_intern (aspath);
889 }
890
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000891 return 0;
892
893}
894
paul718e3742002-12-13 20:15:29 +0000895/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000896static int
paul718e3742002-12-13 20:15:29 +0000897bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
898 struct attr *attr, u_char flag, u_char *startp)
899{
900 bgp_size_t total;
901
902 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
903
904 /* Flag check. */
905 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
906 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
907 {
908 zlog (peer->log, LOG_ERR,
909 "Origin attribute flag isn't transitive %d", flag);
910 bgp_notify_send_with_data (peer,
911 BGP_NOTIFY_UPDATE_ERR,
912 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
913 startp, total);
914 return -1;
915 }
916
917 /* Check nexthop attribute length. */
918 if (length != 4)
919 {
920 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
921 length);
922
923 bgp_notify_send_with_data (peer,
924 BGP_NOTIFY_UPDATE_ERR,
925 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
926 startp, total);
927 return -1;
928 }
929
930 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
931 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
932
933 return 0;
934}
935
936/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000937static int
paul718e3742002-12-13 20:15:29 +0000938bgp_attr_med (struct peer *peer, bgp_size_t length,
939 struct attr *attr, u_char flag, u_char *startp)
940{
941 bgp_size_t total;
942
943 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
944
945 /* Length check. */
946 if (length != 4)
947 {
948 zlog (peer->log, LOG_ERR,
949 "MED attribute length isn't four [%d]", length);
950
951 bgp_notify_send_with_data (peer,
952 BGP_NOTIFY_UPDATE_ERR,
953 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
954 startp, total);
955 return -1;
956 }
957
958 attr->med = stream_getl (peer->ibuf);
959
960 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
961
962 return 0;
963}
964
965/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000966static int
paul718e3742002-12-13 20:15:29 +0000967bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
968 struct attr *attr, u_char flag)
969{
970 /* If it is contained in an UPDATE message that is received from an
971 external peer, then this attribute MUST be ignored by the
972 receiving speaker. */
973 if (peer_sort (peer) == BGP_PEER_EBGP)
974 {
paul9985f832005-02-09 15:51:56 +0000975 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000976 return 0;
977 }
978
979 if (length == 4)
980 attr->local_pref = stream_getl (peer->ibuf);
981 else
982 attr->local_pref = 0;
983
984 /* Set atomic aggregate flag. */
985 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
986
987 return 0;
988}
989
990/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000991static int
paul718e3742002-12-13 20:15:29 +0000992bgp_attr_atomic (struct peer *peer, bgp_size_t length,
993 struct attr *attr, u_char flag)
994{
995 if (length != 0)
996 {
997 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
998
999 bgp_notify_send (peer,
1000 BGP_NOTIFY_UPDATE_ERR,
1001 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1002 return -1;
1003 }
1004
1005 /* Set atomic aggregate flag. */
1006 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1007
1008 return 0;
1009}
1010
1011/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001012static int
paul718e3742002-12-13 20:15:29 +00001013bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1014 struct attr *attr, u_char flag)
1015{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001016 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001017 struct attr_extra *attre = bgp_attr_extra_get (attr);
1018
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001019 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1020 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1021 wantedlen = 8;
1022
1023 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001024 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001025 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001026
1027 bgp_notify_send (peer,
1028 BGP_NOTIFY_UPDATE_ERR,
1029 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1030 return -1;
1031 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001032
1033 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1034 attre->aggregator_as = stream_getl (peer->ibuf);
1035 else
1036 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001037 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001038
1039 /* Set atomic aggregate flag. */
1040 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1041
1042 return 0;
1043}
1044
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001045/* New Aggregator attribute */
1046static int
1047bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1048 struct attr *attr, as_t *as4_aggregator_as,
1049 struct in_addr *as4_aggregator_addr)
1050{
1051 if (length != 8)
1052 {
1053 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1054
1055 bgp_notify_send (peer,
1056 BGP_NOTIFY_UPDATE_ERR,
1057 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1058 return -1;
1059 }
1060 *as4_aggregator_as = stream_getl (peer->ibuf);
1061 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1062
1063 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1064
1065 return 0;
1066}
1067
1068/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1069 */
1070static int
1071bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1072 struct aspath *as4_path, as_t as4_aggregator,
1073 struct in_addr *as4_aggregator_addr)
1074{
1075 int ignore_as4_path = 0;
1076 struct aspath *newpath;
1077 struct attr_extra *attre = attr->extra;
1078
1079 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1080 {
1081 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1082 * if given.
1083 * It is worth a warning though, because the peer really
1084 * should not send them
1085 */
1086 if (BGP_DEBUG(as4, AS4))
1087 {
1088 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1089 zlog_debug ("[AS4] %s %s AS4_PATH",
1090 peer->host, "AS4 capable peer, yet it sent");
1091
1092 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1093 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1094 peer->host, "AS4 capable peer, yet it sent");
1095 }
1096
1097 return 0;
1098 }
1099
1100 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1101 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1102 {
1103 /* Hu? This is not supposed to happen at all!
1104 * got as4_path and no aspath,
1105 * This should already
1106 * have been handled by 'well known attributes missing'
1107 * But... yeah, paranoia
1108 * Take this as a "malformed attribute"
1109 */
1110 zlog (peer->log, LOG_ERR,
1111 "%s BGP not AS4 capable peer sent AS4_PATH but"
1112 " no AS_PATH, cant do anything here", peer->host);
1113 bgp_notify_send (peer,
1114 BGP_NOTIFY_UPDATE_ERR,
1115 BGP_NOTIFY_UPDATE_MAL_ATTR);
1116 return -1;
1117 }
1118
1119 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1120 * because that may override AS4_PATH
1121 */
1122 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1123 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001124 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1125 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001126 assert (attre);
1127
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001128 /* received both.
1129 * if the as_number in aggregator is not AS_TRANS,
1130 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1131 * and the Aggregator shall be taken as
1132 * info on the aggregating node, and the AS_PATH
1133 * shall be taken as the AS_PATH
1134 * otherwise
1135 * the Aggregator shall be ignored and the
1136 * AS4_AGGREGATOR shall be taken as the
1137 * Aggregating node and the AS_PATH is to be
1138 * constructed "as in all other cases"
1139 */
1140 if ( attre->aggregator_as != BGP_AS_TRANS )
1141 {
1142 /* ignore */
1143 if ( BGP_DEBUG(as4, AS4))
1144 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1145 " send AGGREGATOR != AS_TRANS and"
1146 " AS4_AGGREGATOR, so ignore"
1147 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1148 ignore_as4_path = 1;
1149 }
1150 else
1151 {
1152 /* "New_aggregator shall be taken as aggregator" */
1153 attre->aggregator_as = as4_aggregator;
1154 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1155 }
1156 }
1157 else
1158 {
1159 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1160 * That is bogus - but reading the conditions
1161 * we have to handle AS4_AGGREGATOR as if it were
1162 * AGGREGATOR in that case
1163 */
1164 if ( BGP_DEBUG(as4, AS4))
1165 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1166 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1167 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001168 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001169 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1170 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1171 }
1172 }
1173
1174 /* need to reconcile NEW_AS_PATH and AS_PATH */
1175 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1176 {
1177 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1178 aspath_unintern (attr->aspath);
1179 attr->aspath = aspath_intern (newpath);
1180 }
1181 return 0;
1182}
1183
paul718e3742002-12-13 20:15:29 +00001184/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001185static int
paul718e3742002-12-13 20:15:29 +00001186bgp_attr_community (struct peer *peer, bgp_size_t length,
1187 struct attr *attr, u_char flag)
1188{
1189 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001190 {
1191 attr->community = NULL;
1192 return 0;
1193 }
Paul Jakmafc097162010-12-05 17:17:26 +00001194
1195 attr->community =
1196 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1197
1198 /* XXX: fix community_parse to use stream API and remove this */
1199 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001200
Paul Jakmafc097162010-12-05 17:17:26 +00001201 if (!attr->community)
1202 return -1;
1203
paul718e3742002-12-13 20:15:29 +00001204 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1205
1206 return 0;
1207}
1208
1209/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001210static int
paul718e3742002-12-13 20:15:29 +00001211bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1212 struct attr *attr, u_char flag)
1213{
1214 if (length != 4)
1215 {
1216 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1217
1218 bgp_notify_send (peer,
1219 BGP_NOTIFY_UPDATE_ERR,
1220 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1221 return -1;
1222 }
1223
Paul Jakmafb982c22007-05-04 20:15:47 +00001224 (bgp_attr_extra_get (attr))->originator_id.s_addr
1225 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001226
1227 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1228
1229 return 0;
1230}
1231
1232/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001233static int
paul718e3742002-12-13 20:15:29 +00001234bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1235 struct attr *attr, u_char flag)
1236{
1237 /* Check length. */
1238 if (length % 4)
1239 {
1240 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1241
1242 bgp_notify_send (peer,
1243 BGP_NOTIFY_UPDATE_ERR,
1244 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1245 return -1;
1246 }
1247
Paul Jakmafb982c22007-05-04 20:15:47 +00001248 (bgp_attr_extra_get (attr))->cluster
1249 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001250
paul9985f832005-02-09 15:51:56 +00001251 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001252
1253 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1254
1255 return 0;
1256}
1257
1258/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001259int
paul718e3742002-12-13 20:15:29 +00001260bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1261 struct bgp_nlri *mp_update)
1262{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001263 afi_t afi;
1264 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001265 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001266 size_t start;
paul718e3742002-12-13 20:15:29 +00001267 int ret;
1268 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001269 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001270
1271 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001272 s = BGP_INPUT(peer);
1273 start = stream_get_getp(s);
1274
1275 /* safe to read statically sized header? */
1276#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001277#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001278 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001279 {
1280 zlog_info ("%s: %s sent invalid length, %lu",
1281 __func__, peer->host, (unsigned long)length);
1282 return -1;
1283 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001284
paul718e3742002-12-13 20:15:29 +00001285 /* Load AFI, SAFI. */
1286 afi = stream_getw (s);
1287 safi = stream_getc (s);
1288
1289 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001290 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001291
Paul Jakma03292802008-06-07 20:37:10 +00001292 if (LEN_LEFT < attre->mp_nexthop_len)
1293 {
1294 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1295 __func__, peer->host, attre->mp_nexthop_len);
1296 return -1;
1297 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001298
paul718e3742002-12-13 20:15:29 +00001299 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001300 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001301 {
1302 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001303 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001304 /* Probably needed for RFC 2283 */
1305 if (attr->nexthop.s_addr == 0)
1306 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001307 break;
1308 case 12:
1309 {
1310 u_int32_t rd_high;
1311 u_int32_t rd_low;
1312
1313 rd_high = stream_getl (s);
1314 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001315 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001316 }
1317 break;
1318#ifdef HAVE_IPV6
1319 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001320 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001321 break;
1322 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001323 stream_get (&attre->mp_nexthop_global, s, 16);
1324 stream_get (&attre->mp_nexthop_local, s, 16);
1325 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001326 {
1327 char buf1[INET6_ADDRSTRLEN];
1328 char buf2[INET6_ADDRSTRLEN];
1329
1330 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001331 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 +00001332 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001333 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001334 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001335 buf2, INET6_ADDRSTRLEN));
1336
Paul Jakmafb982c22007-05-04 20:15:47 +00001337 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001338 }
1339 break;
1340#endif /* HAVE_IPV6 */
1341 default:
Paul Jakma03292802008-06-07 20:37:10 +00001342 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1343 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001344 return -1;
paul718e3742002-12-13 20:15:29 +00001345 }
1346
Paul Jakma03292802008-06-07 20:37:10 +00001347 if (!LEN_LEFT)
1348 {
1349 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1350 __func__, peer->host);
1351 return -1;
1352 }
paul718e3742002-12-13 20:15:29 +00001353
Paul Jakma6e4ab122007-04-10 19:36:48 +00001354 {
1355 u_char val;
1356 if ((val = stream_getc (s)))
1357 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1358 peer->host, val);
1359 }
1360
1361 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001362 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001363 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001364 {
1365 zlog_info ("%s: (%s) Failed to read NLRI",
1366 __func__, peer->host);
1367 return -1;
1368 }
paul718e3742002-12-13 20:15:29 +00001369
1370 if (safi != BGP_SAFI_VPNV4)
1371 {
1372 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001373 if (ret < 0)
1374 {
1375 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1376 __func__, peer->host);
1377 return -1;
1378 }
paul718e3742002-12-13 20:15:29 +00001379 }
1380
1381 mp_update->afi = afi;
1382 mp_update->safi = safi;
1383 mp_update->nlri = stream_pnt (s);
1384 mp_update->length = nlri_len;
1385
paul9985f832005-02-09 15:51:56 +00001386 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001387
1388 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001389#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001390}
1391
1392/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001393int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001394bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001395 struct bgp_nlri *mp_withdraw)
1396{
1397 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001398 afi_t afi;
1399 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001400 u_int16_t withdraw_len;
1401 int ret;
1402
1403 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001404
1405#define BGP_MP_UNREACH_MIN_SIZE 3
1406 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1407 return -1;
1408
paul718e3742002-12-13 20:15:29 +00001409 afi = stream_getw (s);
1410 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001411
1412 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001413
1414 if (safi != BGP_SAFI_VPNV4)
1415 {
1416 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1417 if (ret < 0)
1418 return -1;
1419 }
1420
1421 mp_withdraw->afi = afi;
1422 mp_withdraw->safi = safi;
1423 mp_withdraw->nlri = stream_pnt (s);
1424 mp_withdraw->length = withdraw_len;
1425
paul9985f832005-02-09 15:51:56 +00001426 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001427
1428 return 0;
1429}
1430
1431/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001432static int
paul718e3742002-12-13 20:15:29 +00001433bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1434 struct attr *attr, u_char flag)
1435{
1436 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001437 {
1438 if (attr->extra)
1439 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001440 /* Empty extcomm doesn't seem to be invalid per se */
1441 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001442 }
Paul Jakmafc097162010-12-05 17:17:26 +00001443
1444 (bgp_attr_extra_get (attr))->ecommunity =
1445 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1446 /* XXX: fix ecommunity_parse to use stream API */
1447 stream_forward_getp (peer->ibuf, length);
1448
1449 if (!attr->extra->ecommunity)
1450 return -1;
1451
paul718e3742002-12-13 20:15:29 +00001452 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1453
1454 return 0;
1455}
1456
1457/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001458static int
paul718e3742002-12-13 20:15:29 +00001459bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1460 u_char type, bgp_size_t length, u_char *startp)
1461{
1462 bgp_size_t total;
1463 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001464 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001465
hassof4184462005-02-01 20:13:16 +00001466 if (BGP_DEBUG (normal, NORMAL))
1467 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1468 peer->host, type, length);
1469
paul718e3742002-12-13 20:15:29 +00001470 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001471 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001472 "Unknown attribute type %d length %d is received", type, length);
1473
1474 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001475 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001476
1477 /* Adjest total length to include type and length. */
1478 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1479
1480 /* If any of the mandatory well-known attributes are not recognized,
1481 then the Error Subcode is set to Unrecognized Well-known
1482 Attribute. The Data field contains the unrecognized attribute
1483 (type, length and value). */
1484 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1485 {
1486 /* Adjust startp to do not include flag value. */
1487 bgp_notify_send_with_data (peer,
1488 BGP_NOTIFY_UPDATE_ERR,
1489 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1490 startp, total);
1491 return -1;
1492 }
1493
1494 /* Unrecognized non-transitive optional attributes must be quietly
1495 ignored and not passed along to other BGP peers. */
1496 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1497 return 0;
1498
1499 /* If a path with recognized transitive optional attribute is
1500 accepted and passed along to other BGP peers and the Partial bit
1501 in the Attribute Flags octet is set to 1 by some previous AS, it
1502 is not set back to 0 by the current AS. */
1503 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1504
1505 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001506 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001507 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001508
Paul Jakmafb982c22007-05-04 20:15:47 +00001509 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001510
1511 if (transit->val)
1512 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1513 transit->length + total);
1514 else
1515 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1516
1517 memcpy (transit->val + transit->length, startp, total);
1518 transit->length += total;
1519
1520 return 0;
1521}
1522
1523/* Read attribute of update packet. This function is called from
1524 bgp_update() in bgpd.c. */
1525int
1526bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1527 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1528{
1529 int ret;
1530 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001531 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001532 bgp_size_t length;
1533 u_char *startp, *endp;
1534 u_char *attr_endp;
1535 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001536 /* we need the as4_path only until we have synthesized the as_path with it */
1537 /* same goes for as4_aggregator */
1538 struct aspath *as4_path = NULL;
1539 as_t as4_aggregator = 0;
1540 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001541
1542 /* Initialize bitmap. */
1543 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1544
1545 /* End pointer of BGP attribute. */
1546 endp = BGP_INPUT_PNT (peer) + size;
1547
1548 /* Get attributes to the end of attribute length. */
1549 while (BGP_INPUT_PNT (peer) < endp)
1550 {
1551 /* Check remaining length check.*/
1552 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1553 {
gdtc29fdba2004-12-09 14:46:46 +00001554 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001555 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001556 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001557 peer->host,
1558 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001559
1560 bgp_notify_send (peer,
1561 BGP_NOTIFY_UPDATE_ERR,
1562 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1563 return -1;
1564 }
1565
1566 /* Fetch attribute flag and type. */
1567 startp = BGP_INPUT_PNT (peer);
1568 flag = stream_getc (BGP_INPUT (peer));
1569 type = stream_getc (BGP_INPUT (peer));
1570
Paul Jakma370b64a2007-12-22 16:49:52 +00001571 /* Check whether Extended-Length applies and is in bounds */
1572 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1573 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1574 {
1575 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001576 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001577 peer->host,
1578 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1579
1580 bgp_notify_send (peer,
1581 BGP_NOTIFY_UPDATE_ERR,
1582 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1583 return -1;
1584 }
1585
paul718e3742002-12-13 20:15:29 +00001586 /* Check extended attribue length bit. */
1587 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1588 length = stream_getw (BGP_INPUT (peer));
1589 else
1590 length = stream_getc (BGP_INPUT (peer));
1591
1592 /* If any attribute appears more than once in the UPDATE
1593 message, then the Error Subcode is set to Malformed Attribute
1594 List. */
1595
1596 if (CHECK_BITMAP (seen, type))
1597 {
1598 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001599 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001600 peer->host, type);
1601
1602 bgp_notify_send (peer,
1603 BGP_NOTIFY_UPDATE_ERR,
1604 BGP_NOTIFY_UPDATE_MAL_ATTR);
1605 return -1;
1606 }
1607
1608 /* Set type to bitmap to check duplicate attribute. `type' is
1609 unsigned char so it never overflow bitmap range. */
1610
1611 SET_BITMAP (seen, type);
1612
1613 /* Overflow check. */
1614 attr_endp = BGP_INPUT_PNT (peer) + length;
1615
1616 if (attr_endp > endp)
1617 {
1618 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001619 "%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 +00001620 bgp_notify_send (peer,
1621 BGP_NOTIFY_UPDATE_ERR,
1622 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1623 return -1;
1624 }
1625
1626 /* OK check attribute and store it's value. */
1627 switch (type)
1628 {
1629 case BGP_ATTR_ORIGIN:
1630 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1631 break;
1632 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001633 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1634 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001635 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001636 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001637 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1638 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001639 break;
paul718e3742002-12-13 20:15:29 +00001640 case BGP_ATTR_NEXT_HOP:
1641 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1642 break;
1643 case BGP_ATTR_MULTI_EXIT_DISC:
1644 ret = bgp_attr_med (peer, length, attr, flag, startp);
1645 break;
1646 case BGP_ATTR_LOCAL_PREF:
1647 ret = bgp_attr_local_pref (peer, length, attr, flag);
1648 break;
1649 case BGP_ATTR_ATOMIC_AGGREGATE:
1650 ret = bgp_attr_atomic (peer, length, attr, flag);
1651 break;
1652 case BGP_ATTR_AGGREGATOR:
1653 ret = bgp_attr_aggregator (peer, length, attr, flag);
1654 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001655 case BGP_ATTR_AS4_AGGREGATOR:
1656 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1657 break;
paul718e3742002-12-13 20:15:29 +00001658 case BGP_ATTR_COMMUNITIES:
1659 ret = bgp_attr_community (peer, length, attr, flag);
1660 break;
1661 case BGP_ATTR_ORIGINATOR_ID:
1662 ret = bgp_attr_originator_id (peer, length, attr, flag);
1663 break;
1664 case BGP_ATTR_CLUSTER_LIST:
1665 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1666 break;
1667 case BGP_ATTR_MP_REACH_NLRI:
1668 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1669 break;
1670 case BGP_ATTR_MP_UNREACH_NLRI:
1671 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1672 break;
1673 case BGP_ATTR_EXT_COMMUNITIES:
1674 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1675 break;
1676 default:
1677 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1678 break;
1679 }
1680
1681 /* If error occured immediately return to the caller. */
1682 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001683 {
1684 zlog (peer->log, LOG_WARNING,
1685 "%s: Attribute %s, parse error",
1686 peer->host,
1687 LOOKUP (attr_str, type));
1688 bgp_notify_send (peer,
1689 BGP_NOTIFY_UPDATE_ERR,
1690 BGP_NOTIFY_UPDATE_MAL_ATTR);
1691 return ret;
1692 }
paul718e3742002-12-13 20:15:29 +00001693
1694 /* Check the fetched length. */
1695 if (BGP_INPUT_PNT (peer) != attr_endp)
1696 {
1697 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001698 "%s: BGP attribute %s, fetch error",
1699 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001700 bgp_notify_send (peer,
1701 BGP_NOTIFY_UPDATE_ERR,
1702 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1703 return -1;
1704 }
1705 }
1706
1707 /* Check final read pointer is same as end pointer. */
1708 if (BGP_INPUT_PNT (peer) != endp)
1709 {
1710 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001711 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001712 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001713 bgp_notify_send (peer,
1714 BGP_NOTIFY_UPDATE_ERR,
1715 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1716 return -1;
1717 }
1718
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001719 /*
1720 * At this place we can see whether we got AS4_PATH and/or
1721 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1722 * We can not do this before we've read all attributes because
1723 * the as4 handling does not say whether AS4_PATH has to be sent
1724 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1725 * in relationship to AGGREGATOR.
1726 * So, to be defensive, we are not relying on any order and read
1727 * all attributes first, including these 32bit ones, and now,
1728 * afterwards, we look what and if something is to be done for as4.
1729 */
1730 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1731 as4_aggregator, &as4_aggregator_addr))
1732 return -1;
1733
1734 /* At this stage, we have done all fiddling with as4, and the
1735 * resulting info is in attr->aggregator resp. attr->aspath
1736 * so we can chuck as4_aggregator and as4_path alltogether in
1737 * order to save memory
1738 */
1739 if ( as4_path )
1740 {
1741 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1742 as4_path = NULL;
1743 /* The flag that we got this is still there, but that does not
1744 * do any trouble
1745 */
1746 }
1747 /*
1748 * The "rest" of the code does nothing with as4_aggregator.
1749 * there is no memory attached specifically which is not part
1750 * of the attr.
1751 * so ignoring just means do nothing.
1752 */
1753 /*
1754 * Finally do the checks on the aspath we did not do yet
1755 * because we waited for a potentially synthesized aspath.
1756 */
1757 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1758 {
1759 ret = bgp_attr_aspath_check( peer, attr );
1760 if ( ret < 0 )
1761 return ret;
1762 }
1763
paul718e3742002-12-13 20:15:29 +00001764 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001765 if (attr->extra && attr->extra->transit)
1766 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001767
1768 return 0;
1769}
1770
1771/* Well-known attribute check. */
1772int
1773bgp_attr_check (struct peer *peer, struct attr *attr)
1774{
1775 u_char type = 0;
1776
1777 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1778 type = BGP_ATTR_ORIGIN;
1779
1780 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1781 type = BGP_ATTR_AS_PATH;
1782
1783 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1784 type = BGP_ATTR_NEXT_HOP;
1785
1786 if (peer_sort (peer) == BGP_PEER_IBGP
1787 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1788 type = BGP_ATTR_LOCAL_PREF;
1789
1790 if (type)
1791 {
1792 zlog (peer->log, LOG_WARNING,
1793 "%s Missing well-known attribute %d.",
1794 peer->host, type);
1795 bgp_notify_send_with_data (peer,
1796 BGP_NOTIFY_UPDATE_ERR,
1797 BGP_NOTIFY_UPDATE_MISS_ATTR,
1798 &type, 1);
1799 return -1;
1800 }
1801 return 0;
1802}
1803
1804int stream_put_prefix (struct stream *, struct prefix *);
1805
1806/* Make attribute packet. */
1807bgp_size_t
1808bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1809 struct stream *s, struct attr *attr, struct prefix *p,
1810 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001811 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001812{
paulfe69a502005-09-10 16:55:02 +00001813 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001814 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001815 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001816 int send_as4_path = 0;
1817 int send_as4_aggregator = 0;
1818 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001819
1820 if (! bgp)
1821 bgp = bgp_get_default ();
1822
1823 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001824 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001825
1826 /* Origin attribute. */
1827 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1828 stream_putc (s, BGP_ATTR_ORIGIN);
1829 stream_putc (s, 1);
1830 stream_putc (s, attr->origin);
1831
1832 /* AS path attribute. */
1833
1834 /* If remote-peer is EBGP */
1835 if (peer_sort (peer) == BGP_PEER_EBGP
1836 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001837 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001838 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001839 {
1840 aspath = aspath_dup (attr->aspath);
1841
1842 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1843 {
1844 /* Strip the confed info, and then stuff our path CONFED_ID
1845 on the front */
1846 aspath = aspath_delete_confed_seq (aspath);
1847 aspath = aspath_add_seq (aspath, bgp->confed_id);
1848 }
1849 else
1850 {
1851 aspath = aspath_add_seq (aspath, peer->local_as);
1852 if (peer->change_local_as)
1853 aspath = aspath_add_seq (aspath, peer->change_local_as);
1854 }
1855 }
1856 else if (peer_sort (peer) == BGP_PEER_CONFED)
1857 {
1858 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1859 aspath = aspath_dup (attr->aspath);
1860 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1861 }
1862 else
1863 aspath = attr->aspath;
1864
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001865 /* If peer is not AS4 capable, then:
1866 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1867 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1868 * types are in it (i.e. exclude them if they are there)
1869 * AND do this only if there is at least one asnum > 65535 in the path!
1870 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1871 * all ASnums > 65535 to BGP_AS_TRANS
1872 */
paul718e3742002-12-13 20:15:29 +00001873
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001874 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1875 stream_putc (s, BGP_ATTR_AS_PATH);
1876 aspath_sizep = stream_get_endp (s);
1877 stream_putw (s, 0);
1878 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1879
1880 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1881 * in the path
1882 */
1883 if (!use32bit && aspath_has_as4 (aspath))
1884 send_as4_path = 1; /* we'll do this later, at the correct place */
1885
paul718e3742002-12-13 20:15:29 +00001886 /* Nexthop attribute. */
1887 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1888 {
1889 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1890 stream_putc (s, BGP_ATTR_NEXT_HOP);
1891 stream_putc (s, 4);
1892 if (safi == SAFI_MPLS_VPN)
1893 {
1894 if (attr->nexthop.s_addr == 0)
1895 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1896 else
1897 stream_put_ipv4 (s, attr->nexthop.s_addr);
1898 }
1899 else
1900 stream_put_ipv4 (s, attr->nexthop.s_addr);
1901 }
1902
1903 /* MED attribute. */
1904 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1905 {
1906 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1907 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1908 stream_putc (s, 4);
1909 stream_putl (s, attr->med);
1910 }
1911
1912 /* Local preference. */
1913 if (peer_sort (peer) == BGP_PEER_IBGP ||
1914 peer_sort (peer) == BGP_PEER_CONFED)
1915 {
1916 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1917 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1918 stream_putc (s, 4);
1919 stream_putl (s, attr->local_pref);
1920 }
1921
1922 /* Atomic aggregate. */
1923 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1924 {
1925 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1926 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1927 stream_putc (s, 0);
1928 }
1929
1930 /* Aggregator. */
1931 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1932 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001933 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001934
1935 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001936 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1937 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001938
1939 if (use32bit)
1940 {
1941 /* AS4 capable peer */
1942 stream_putc (s, 8);
1943 stream_putl (s, attr->extra->aggregator_as);
1944 }
1945 else
1946 {
1947 /* 2-byte AS peer */
1948 stream_putc (s, 6);
1949
1950 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1951 if ( attr->extra->aggregator_as > 65535 )
1952 {
1953 stream_putw (s, BGP_AS_TRANS);
1954
1955 /* we have to send AS4_AGGREGATOR, too.
1956 * we'll do that later in order to send attributes in ascending
1957 * order.
1958 */
1959 send_as4_aggregator = 1;
1960 }
1961 else
1962 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1963 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001964 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001965 }
1966
1967 /* Community attribute. */
1968 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1969 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1970 {
1971 if (attr->community->size * 4 > 255)
1972 {
1973 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1974 stream_putc (s, BGP_ATTR_COMMUNITIES);
1975 stream_putw (s, attr->community->size * 4);
1976 }
1977 else
1978 {
1979 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1980 stream_putc (s, BGP_ATTR_COMMUNITIES);
1981 stream_putc (s, attr->community->size * 4);
1982 }
1983 stream_put (s, attr->community->val, attr->community->size * 4);
1984 }
1985
1986 /* Route Reflector. */
1987 if (peer_sort (peer) == BGP_PEER_IBGP
1988 && from
1989 && peer_sort (from) == BGP_PEER_IBGP)
1990 {
1991 /* Originator ID. */
1992 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1993 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1994 stream_putc (s, 4);
1995
1996 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001997 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001998 else
1999 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002000
2001 /* Cluster list. */
2002 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2003 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2004
Paul Jakma9eda90c2007-08-30 13:36:17 +00002005 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002006 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002007 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002008 /* If this peer configuration's parent BGP has cluster_id. */
2009 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2010 stream_put_in_addr (s, &bgp->cluster_id);
2011 else
2012 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002013 stream_put (s, attr->extra->cluster->list,
2014 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002015 }
2016 else
2017 {
2018 stream_putc (s, 4);
2019 /* If this peer configuration's parent BGP has cluster_id. */
2020 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2021 stream_put_in_addr (s, &bgp->cluster_id);
2022 else
2023 stream_put_in_addr (s, &bgp->router_id);
2024 }
2025 }
2026
2027#ifdef HAVE_IPV6
2028 /* If p is IPv6 address put it into attribute. */
2029 if (p->family == AF_INET6)
2030 {
2031 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002032 struct attr_extra *attre = attr->extra;
2033
2034 assert (attr->extra);
2035
paul718e3742002-12-13 20:15:29 +00002036 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2037 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002038 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002039 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002040 stream_putw (s, AFI_IP6); /* AFI */
2041 stream_putc (s, safi); /* SAFI */
2042
Paul Jakmafb982c22007-05-04 20:15:47 +00002043 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002044
Paul Jakmafb982c22007-05-04 20:15:47 +00002045 if (attre->mp_nexthop_len == 16)
2046 stream_put (s, &attre->mp_nexthop_global, 16);
2047 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002048 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002049 stream_put (s, &attre->mp_nexthop_global, 16);
2050 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002051 }
2052
2053 /* SNPA */
2054 stream_putc (s, 0);
2055
paul718e3742002-12-13 20:15:29 +00002056 /* Prefix write. */
2057 stream_put_prefix (s, p);
2058
2059 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002060 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002061 }
2062#endif /* HAVE_IPV6 */
2063
2064 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2065 {
2066 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002067
2068 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2069 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002070 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002072 stream_putw (s, AFI_IP); /* AFI */
2073 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2074
2075 stream_putc (s, 4);
2076 stream_put_ipv4 (s, attr->nexthop.s_addr);
2077
2078 /* SNPA */
2079 stream_putc (s, 0);
2080
paul718e3742002-12-13 20:15:29 +00002081 /* Prefix write. */
2082 stream_put_prefix (s, p);
2083
2084 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002085 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002086 }
2087
2088 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2089 {
2090 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002091
2092 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2093 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002094 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002095 stream_putc (s, 0); /* Length of this attribute. */
2096 stream_putw (s, AFI_IP); /* AFI */
2097 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2098
2099 stream_putc (s, 12);
2100 stream_putl (s, 0);
2101 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002102 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002103
2104 /* SNPA */
2105 stream_putc (s, 0);
2106
paul718e3742002-12-13 20:15:29 +00002107 /* Tag, RD, Prefix write. */
2108 stream_putc (s, p->prefixlen + 88);
2109 stream_put (s, tag, 3);
2110 stream_put (s, prd->val, 8);
2111 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2112
2113 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002114 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002115 }
2116
2117 /* Extended Communities attribute. */
2118 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2119 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2120 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002121 struct attr_extra *attre = attr->extra;
2122
2123 assert (attre);
2124
2125 if (peer_sort (peer) == BGP_PEER_IBGP
2126 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002127 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002128 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002129 {
2130 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2131 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002132 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002133 }
2134 else
2135 {
2136 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2137 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002138 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002139 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002140 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002141 }
2142 else
2143 {
paul5228ad22004-06-04 17:58:18 +00002144 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002145 int tbit;
2146 int ecom_tr_size = 0;
2147 int i;
2148
Paul Jakmafb982c22007-05-04 20:15:47 +00002149 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002150 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002151 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002152 tbit = *pnt;
2153
2154 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2155 continue;
2156
2157 ecom_tr_size++;
2158 }
2159
2160 if (ecom_tr_size)
2161 {
2162 if (ecom_tr_size * 8 > 255)
2163 {
2164 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2165 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2166 stream_putw (s, ecom_tr_size * 8);
2167 }
2168 else
2169 {
2170 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2171 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2172 stream_putc (s, ecom_tr_size * 8);
2173 }
2174
Paul Jakmafb982c22007-05-04 20:15:47 +00002175 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002176 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002177 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002178 tbit = *pnt;
2179
2180 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2181 continue;
2182
2183 stream_put (s, pnt, 8);
2184 }
2185 }
paul718e3742002-12-13 20:15:29 +00002186 }
paul718e3742002-12-13 20:15:29 +00002187 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002188
2189 if ( send_as4_path )
2190 {
2191 /* If the peer is NOT As4 capable, AND */
2192 /* there are ASnums > 65535 in path THEN
2193 * give out AS4_PATH */
2194
2195 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2196 * path segments!
2197 * Hm, I wonder... confederation things *should* only be at
2198 * the beginning of an aspath, right? Then we should use
2199 * aspath_delete_confed_seq for this, because it is already
2200 * there! (JK)
2201 * Folks, talk to me: what is reasonable here!?
2202 */
2203 aspath = aspath_delete_confed_seq (aspath);
2204
2205 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2206 stream_putc (s, BGP_ATTR_AS4_PATH);
2207 aspath_sizep = stream_get_endp (s);
2208 stream_putw (s, 0);
2209 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2210 }
2211
2212 if (aspath != attr->aspath)
2213 aspath_free (aspath);
2214
2215 if ( send_as4_aggregator )
2216 {
2217 assert (attr->extra);
2218
2219 /* send AS4_AGGREGATOR, at this place */
2220 /* this section of code moved here in order to ensure the correct
2221 * *ascending* order of attributes
2222 */
2223 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2224 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2225 stream_putc (s, 8);
2226 stream_putl (s, attr->extra->aggregator_as);
2227 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2228 }
Paul Jakma41367172007-08-06 15:24:51 +00002229
paul718e3742002-12-13 20:15:29 +00002230 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002231 if (attr->extra && attr->extra->transit)
2232 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002233
2234 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002235 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002236}
2237
2238bgp_size_t
2239bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2240 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002241 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002242{
2243 unsigned long cp;
2244 unsigned long attrlen_pnt;
2245 bgp_size_t size;
2246
paul9985f832005-02-09 15:51:56 +00002247 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002248
2249 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2250 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2251
paul9985f832005-02-09 15:51:56 +00002252 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002253 stream_putc (s, 0); /* Length of this attribute. */
2254
2255 stream_putw (s, family2afi (p->family));
2256
2257 if (safi == SAFI_MPLS_VPN)
2258 {
2259 /* SAFI */
2260 stream_putc (s, BGP_SAFI_VPNV4);
2261
2262 /* prefix. */
2263 stream_putc (s, p->prefixlen + 88);
2264 stream_put (s, tag, 3);
2265 stream_put (s, prd->val, 8);
2266 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2267 }
2268 else
2269 {
2270 /* SAFI */
2271 stream_putc (s, safi);
2272
2273 /* prefix */
2274 stream_put_prefix (s, p);
2275 }
2276
2277 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002278 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002279 stream_putc_at (s, attrlen_pnt, size);
2280
paul9985f832005-02-09 15:51:56 +00002281 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002282}
2283
2284/* Initialization of attribute. */
2285void
paulfe69a502005-09-10 16:55:02 +00002286bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002287{
paul718e3742002-12-13 20:15:29 +00002288 aspath_init ();
2289 attrhash_init ();
2290 community_init ();
2291 ecommunity_init ();
2292 cluster_init ();
2293 transit_init ();
2294}
2295
Chris Caputo228da422009-07-18 05:44:03 +00002296void
2297bgp_attr_finish (void)
2298{
2299 aspath_finish ();
2300 attrhash_finish ();
2301 community_finish ();
2302 ecommunity_finish ();
2303 cluster_finish ();
2304 transit_finish ();
2305}
2306
paul718e3742002-12-13 20:15:29 +00002307/* Make attribute packet. */
2308void
paula3845922003-10-18 01:30:50 +00002309bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2310 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002311{
2312 unsigned long cp;
2313 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002314 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002315 struct aspath *aspath;
2316
2317 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002318 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002319
2320 /* Place holder of length. */
2321 stream_putw (s, 0);
2322
2323 /* Origin attribute. */
2324 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2325 stream_putc (s, BGP_ATTR_ORIGIN);
2326 stream_putc (s, 1);
2327 stream_putc (s, attr->origin);
2328
2329 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002330
2331 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2332 stream_putc (s, BGP_ATTR_AS_PATH);
2333 aspath_lenp = stream_get_endp (s);
2334 stream_putw (s, 0);
2335
2336 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002337
2338 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002339 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2340 if(prefix != NULL
2341#ifdef HAVE_IPV6
2342 && prefix->family != AF_INET6
2343#endif /* HAVE_IPV6 */
2344 )
2345 {
2346 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2347 stream_putc (s, BGP_ATTR_NEXT_HOP);
2348 stream_putc (s, 4);
2349 stream_put_ipv4 (s, attr->nexthop.s_addr);
2350 }
paul718e3742002-12-13 20:15:29 +00002351
2352 /* MED attribute. */
2353 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2354 {
2355 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2356 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2357 stream_putc (s, 4);
2358 stream_putl (s, attr->med);
2359 }
2360
2361 /* Local preference. */
2362 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2363 {
2364 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2365 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2366 stream_putc (s, 4);
2367 stream_putl (s, attr->local_pref);
2368 }
2369
2370 /* Atomic aggregate. */
2371 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2372 {
2373 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2374 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2375 stream_putc (s, 0);
2376 }
2377
2378 /* Aggregator. */
2379 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2380 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002381 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002382 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2383 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002384 stream_putc (s, 8);
2385 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002386 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002387 }
2388
2389 /* Community attribute. */
2390 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2391 {
2392 if (attr->community->size * 4 > 255)
2393 {
2394 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2395 stream_putc (s, BGP_ATTR_COMMUNITIES);
2396 stream_putw (s, attr->community->size * 4);
2397 }
2398 else
2399 {
2400 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2401 stream_putc (s, BGP_ATTR_COMMUNITIES);
2402 stream_putc (s, attr->community->size * 4);
2403 }
2404 stream_put (s, attr->community->val, attr->community->size * 4);
2405 }
2406
paula3845922003-10-18 01:30:50 +00002407#ifdef HAVE_IPV6
2408 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002409 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2410 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002411 {
2412 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002413 struct attr_extra *attre = attr->extra;
2414
paula3845922003-10-18 01:30:50 +00002415 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2416 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002417 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002418
2419 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002420 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002421 stream_putw(s, AFI_IP6); /* AFI */
2422 stream_putc(s, SAFI_UNICAST); /* SAFI */
2423
2424 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002425 stream_putc(s, attre->mp_nexthop_len);
2426 stream_put(s, &attre->mp_nexthop_global, 16);
2427 if (attre->mp_nexthop_len == 32)
2428 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002429
2430 /* SNPA */
2431 stream_putc(s, 0);
2432
2433 /* Prefix */
2434 stream_put_prefix(s, prefix);
2435
2436 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002437 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002438 }
2439#endif /* HAVE_IPV6 */
2440
paul718e3742002-12-13 20:15:29 +00002441 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002442 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002443 stream_putw_at (s, cp, len);
2444}