blob: fe2d20e8b81b2fdccd5d29f819dec6b81353bae3 [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,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +0400968 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000969{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +0400970 bgp_size_t total;
971
972 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
973 /* Flag checks. */
974 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
975 {
976 zlog (peer->log, LOG_ERR,
977 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
978 bgp_notify_send_with_data (peer,
979 BGP_NOTIFY_UPDATE_ERR,
980 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
981 startp, total);
982 return -1;
983 }
984 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
985 {
986 zlog (peer->log, LOG_ERR,
987 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
988 bgp_notify_send_with_data (peer,
989 BGP_NOTIFY_UPDATE_ERR,
990 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
991 startp, total);
992 return -1;
993 }
994
paul718e3742002-12-13 20:15:29 +0000995 /* If it is contained in an UPDATE message that is received from an
996 external peer, then this attribute MUST be ignored by the
997 receiving speaker. */
998 if (peer_sort (peer) == BGP_PEER_EBGP)
999 {
paul9985f832005-02-09 15:51:56 +00001000 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001001 return 0;
1002 }
1003
1004 if (length == 4)
1005 attr->local_pref = stream_getl (peer->ibuf);
1006 else
1007 attr->local_pref = 0;
1008
1009 /* Set atomic aggregate flag. */
1010 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1011
1012 return 0;
1013}
1014
1015/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001016static int
paul718e3742002-12-13 20:15:29 +00001017bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1018 struct attr *attr, u_char flag)
1019{
1020 if (length != 0)
1021 {
1022 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1023
1024 bgp_notify_send (peer,
1025 BGP_NOTIFY_UPDATE_ERR,
1026 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1027 return -1;
1028 }
1029
1030 /* Set atomic aggregate flag. */
1031 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1032
1033 return 0;
1034}
1035
1036/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001037static int
paul718e3742002-12-13 20:15:29 +00001038bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1039 struct attr *attr, u_char flag)
1040{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001041 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001042 struct attr_extra *attre = bgp_attr_extra_get (attr);
1043
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001044 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1045 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1046 wantedlen = 8;
1047
1048 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001049 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001050 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001051
1052 bgp_notify_send (peer,
1053 BGP_NOTIFY_UPDATE_ERR,
1054 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1055 return -1;
1056 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001057
1058 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1059 attre->aggregator_as = stream_getl (peer->ibuf);
1060 else
1061 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001062 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001063
1064 /* Set atomic aggregate flag. */
1065 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1066
1067 return 0;
1068}
1069
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001070/* New Aggregator attribute */
1071static int
1072bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1073 struct attr *attr, as_t *as4_aggregator_as,
1074 struct in_addr *as4_aggregator_addr)
1075{
1076 if (length != 8)
1077 {
1078 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1079
1080 bgp_notify_send (peer,
1081 BGP_NOTIFY_UPDATE_ERR,
1082 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1083 return -1;
1084 }
1085 *as4_aggregator_as = stream_getl (peer->ibuf);
1086 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1087
1088 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1089
1090 return 0;
1091}
1092
1093/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1094 */
1095static int
1096bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1097 struct aspath *as4_path, as_t as4_aggregator,
1098 struct in_addr *as4_aggregator_addr)
1099{
1100 int ignore_as4_path = 0;
1101 struct aspath *newpath;
1102 struct attr_extra *attre = attr->extra;
1103
1104 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1105 {
1106 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1107 * if given.
1108 * It is worth a warning though, because the peer really
1109 * should not send them
1110 */
1111 if (BGP_DEBUG(as4, AS4))
1112 {
1113 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1114 zlog_debug ("[AS4] %s %s AS4_PATH",
1115 peer->host, "AS4 capable peer, yet it sent");
1116
1117 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1118 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1119 peer->host, "AS4 capable peer, yet it sent");
1120 }
1121
1122 return 0;
1123 }
1124
1125 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1126 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1127 {
1128 /* Hu? This is not supposed to happen at all!
1129 * got as4_path and no aspath,
1130 * This should already
1131 * have been handled by 'well known attributes missing'
1132 * But... yeah, paranoia
1133 * Take this as a "malformed attribute"
1134 */
1135 zlog (peer->log, LOG_ERR,
1136 "%s BGP not AS4 capable peer sent AS4_PATH but"
1137 " no AS_PATH, cant do anything here", peer->host);
1138 bgp_notify_send (peer,
1139 BGP_NOTIFY_UPDATE_ERR,
1140 BGP_NOTIFY_UPDATE_MAL_ATTR);
1141 return -1;
1142 }
1143
1144 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1145 * because that may override AS4_PATH
1146 */
1147 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1148 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001149 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1150 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001151 assert (attre);
1152
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001153 /* received both.
1154 * if the as_number in aggregator is not AS_TRANS,
1155 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1156 * and the Aggregator shall be taken as
1157 * info on the aggregating node, and the AS_PATH
1158 * shall be taken as the AS_PATH
1159 * otherwise
1160 * the Aggregator shall be ignored and the
1161 * AS4_AGGREGATOR shall be taken as the
1162 * Aggregating node and the AS_PATH is to be
1163 * constructed "as in all other cases"
1164 */
1165 if ( attre->aggregator_as != BGP_AS_TRANS )
1166 {
1167 /* ignore */
1168 if ( BGP_DEBUG(as4, AS4))
1169 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1170 " send AGGREGATOR != AS_TRANS and"
1171 " AS4_AGGREGATOR, so ignore"
1172 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1173 ignore_as4_path = 1;
1174 }
1175 else
1176 {
1177 /* "New_aggregator shall be taken as aggregator" */
1178 attre->aggregator_as = as4_aggregator;
1179 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1180 }
1181 }
1182 else
1183 {
1184 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1185 * That is bogus - but reading the conditions
1186 * we have to handle AS4_AGGREGATOR as if it were
1187 * AGGREGATOR in that case
1188 */
1189 if ( BGP_DEBUG(as4, AS4))
1190 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1191 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1192 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001193 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001194 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1195 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1196 }
1197 }
1198
1199 /* need to reconcile NEW_AS_PATH and AS_PATH */
1200 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1201 {
1202 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1203 aspath_unintern (attr->aspath);
1204 attr->aspath = aspath_intern (newpath);
1205 }
1206 return 0;
1207}
1208
paul718e3742002-12-13 20:15:29 +00001209/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001210static int
paul718e3742002-12-13 20:15:29 +00001211bgp_attr_community (struct peer *peer, bgp_size_t length,
1212 struct attr *attr, u_char flag)
1213{
1214 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001215 {
1216 attr->community = NULL;
1217 return 0;
1218 }
Paul Jakmafc097162010-12-05 17:17:26 +00001219
1220 attr->community =
1221 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1222
1223 /* XXX: fix community_parse to use stream API and remove this */
1224 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001225
Paul Jakmafc097162010-12-05 17:17:26 +00001226 if (!attr->community)
1227 return -1;
1228
paul718e3742002-12-13 20:15:29 +00001229 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1230
1231 return 0;
1232}
1233
1234/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001235static int
paul718e3742002-12-13 20:15:29 +00001236bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1237 struct attr *attr, u_char flag)
1238{
1239 if (length != 4)
1240 {
1241 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1242
1243 bgp_notify_send (peer,
1244 BGP_NOTIFY_UPDATE_ERR,
1245 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1246 return -1;
1247 }
1248
Paul Jakmafb982c22007-05-04 20:15:47 +00001249 (bgp_attr_extra_get (attr))->originator_id.s_addr
1250 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001251
1252 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1253
1254 return 0;
1255}
1256
1257/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001258static int
paul718e3742002-12-13 20:15:29 +00001259bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1260 struct attr *attr, u_char flag)
1261{
1262 /* Check length. */
1263 if (length % 4)
1264 {
1265 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1266
1267 bgp_notify_send (peer,
1268 BGP_NOTIFY_UPDATE_ERR,
1269 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1270 return -1;
1271 }
1272
Paul Jakmafb982c22007-05-04 20:15:47 +00001273 (bgp_attr_extra_get (attr))->cluster
1274 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001275
paul9985f832005-02-09 15:51:56 +00001276 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001277
1278 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1279
1280 return 0;
1281}
1282
1283/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001284int
paul718e3742002-12-13 20:15:29 +00001285bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1286 struct bgp_nlri *mp_update)
1287{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001288 afi_t afi;
1289 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001290 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001291 size_t start;
paul718e3742002-12-13 20:15:29 +00001292 int ret;
1293 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001294 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001295
1296 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001297 s = BGP_INPUT(peer);
1298 start = stream_get_getp(s);
1299
1300 /* safe to read statically sized header? */
1301#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001302#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001303 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001304 {
1305 zlog_info ("%s: %s sent invalid length, %lu",
1306 __func__, peer->host, (unsigned long)length);
1307 return -1;
1308 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001309
paul718e3742002-12-13 20:15:29 +00001310 /* Load AFI, SAFI. */
1311 afi = stream_getw (s);
1312 safi = stream_getc (s);
1313
1314 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001315 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001316
Paul Jakma03292802008-06-07 20:37:10 +00001317 if (LEN_LEFT < attre->mp_nexthop_len)
1318 {
1319 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1320 __func__, peer->host, attre->mp_nexthop_len);
1321 return -1;
1322 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001323
paul718e3742002-12-13 20:15:29 +00001324 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001325 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001326 {
1327 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001328 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001329 /* Probably needed for RFC 2283 */
1330 if (attr->nexthop.s_addr == 0)
1331 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001332 break;
1333 case 12:
1334 {
1335 u_int32_t rd_high;
1336 u_int32_t rd_low;
1337
1338 rd_high = stream_getl (s);
1339 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001340 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001341 }
1342 break;
1343#ifdef HAVE_IPV6
1344 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001345 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001346 break;
1347 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001348 stream_get (&attre->mp_nexthop_global, s, 16);
1349 stream_get (&attre->mp_nexthop_local, s, 16);
1350 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001351 {
1352 char buf1[INET6_ADDRSTRLEN];
1353 char buf2[INET6_ADDRSTRLEN];
1354
1355 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001356 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 +00001357 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001358 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001359 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001360 buf2, INET6_ADDRSTRLEN));
1361
Paul Jakmafb982c22007-05-04 20:15:47 +00001362 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001363 }
1364 break;
1365#endif /* HAVE_IPV6 */
1366 default:
Paul Jakma03292802008-06-07 20:37:10 +00001367 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1368 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001369 return -1;
paul718e3742002-12-13 20:15:29 +00001370 }
1371
Paul Jakma03292802008-06-07 20:37:10 +00001372 if (!LEN_LEFT)
1373 {
1374 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1375 __func__, peer->host);
1376 return -1;
1377 }
paul718e3742002-12-13 20:15:29 +00001378
Paul Jakma6e4ab122007-04-10 19:36:48 +00001379 {
1380 u_char val;
1381 if ((val = stream_getc (s)))
1382 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1383 peer->host, val);
1384 }
1385
1386 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001387 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001388 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001389 {
1390 zlog_info ("%s: (%s) Failed to read NLRI",
1391 __func__, peer->host);
1392 return -1;
1393 }
paul718e3742002-12-13 20:15:29 +00001394
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001395 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001396 {
1397 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001398 if (ret < 0)
1399 {
1400 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1401 __func__, peer->host);
1402 return -1;
1403 }
paul718e3742002-12-13 20:15:29 +00001404 }
1405
1406 mp_update->afi = afi;
1407 mp_update->safi = safi;
1408 mp_update->nlri = stream_pnt (s);
1409 mp_update->length = nlri_len;
1410
paul9985f832005-02-09 15:51:56 +00001411 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001412
1413 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001414#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001415}
1416
1417/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001418int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001419bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001420 struct bgp_nlri *mp_withdraw)
1421{
1422 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001423 afi_t afi;
1424 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001425 u_int16_t withdraw_len;
1426 int ret;
1427
1428 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001429
1430#define BGP_MP_UNREACH_MIN_SIZE 3
1431 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1432 return -1;
1433
paul718e3742002-12-13 20:15:29 +00001434 afi = stream_getw (s);
1435 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001436
1437 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001438
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001439 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001440 {
1441 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1442 if (ret < 0)
1443 return -1;
1444 }
1445
1446 mp_withdraw->afi = afi;
1447 mp_withdraw->safi = safi;
1448 mp_withdraw->nlri = stream_pnt (s);
1449 mp_withdraw->length = withdraw_len;
1450
paul9985f832005-02-09 15:51:56 +00001451 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001452
1453 return 0;
1454}
1455
1456/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001457static int
paul718e3742002-12-13 20:15:29 +00001458bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1459 struct attr *attr, u_char flag)
1460{
1461 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001462 {
1463 if (attr->extra)
1464 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001465 /* Empty extcomm doesn't seem to be invalid per se */
1466 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001467 }
Paul Jakmafc097162010-12-05 17:17:26 +00001468
1469 (bgp_attr_extra_get (attr))->ecommunity =
1470 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1471 /* XXX: fix ecommunity_parse to use stream API */
1472 stream_forward_getp (peer->ibuf, length);
1473
1474 if (!attr->extra->ecommunity)
1475 return -1;
1476
paul718e3742002-12-13 20:15:29 +00001477 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1478
1479 return 0;
1480}
1481
1482/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001483static int
paul718e3742002-12-13 20:15:29 +00001484bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1485 u_char type, bgp_size_t length, u_char *startp)
1486{
1487 bgp_size_t total;
1488 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001489 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001490
hassof4184462005-02-01 20:13:16 +00001491 if (BGP_DEBUG (normal, NORMAL))
1492 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1493 peer->host, type, length);
1494
paul718e3742002-12-13 20:15:29 +00001495 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001496 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001497 "Unknown attribute type %d length %d is received", type, length);
1498
1499 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001500 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001501
1502 /* Adjest total length to include type and length. */
1503 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1504
1505 /* If any of the mandatory well-known attributes are not recognized,
1506 then the Error Subcode is set to Unrecognized Well-known
1507 Attribute. The Data field contains the unrecognized attribute
1508 (type, length and value). */
1509 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1510 {
1511 /* Adjust startp to do not include flag value. */
1512 bgp_notify_send_with_data (peer,
1513 BGP_NOTIFY_UPDATE_ERR,
1514 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1515 startp, total);
1516 return -1;
1517 }
1518
1519 /* Unrecognized non-transitive optional attributes must be quietly
1520 ignored and not passed along to other BGP peers. */
1521 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1522 return 0;
1523
1524 /* If a path with recognized transitive optional attribute is
1525 accepted and passed along to other BGP peers and the Partial bit
1526 in the Attribute Flags octet is set to 1 by some previous AS, it
1527 is not set back to 0 by the current AS. */
1528 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1529
1530 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001531 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001532 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001533
Paul Jakmafb982c22007-05-04 20:15:47 +00001534 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001535
1536 if (transit->val)
1537 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1538 transit->length + total);
1539 else
1540 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1541
1542 memcpy (transit->val + transit->length, startp, total);
1543 transit->length += total;
1544
1545 return 0;
1546}
1547
1548/* Read attribute of update packet. This function is called from
1549 bgp_update() in bgpd.c. */
1550int
1551bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1552 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1553{
1554 int ret;
1555 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001556 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001557 bgp_size_t length;
1558 u_char *startp, *endp;
1559 u_char *attr_endp;
1560 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001561 /* we need the as4_path only until we have synthesized the as_path with it */
1562 /* same goes for as4_aggregator */
1563 struct aspath *as4_path = NULL;
1564 as_t as4_aggregator = 0;
1565 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001566
1567 /* Initialize bitmap. */
1568 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1569
1570 /* End pointer of BGP attribute. */
1571 endp = BGP_INPUT_PNT (peer) + size;
1572
1573 /* Get attributes to the end of attribute length. */
1574 while (BGP_INPUT_PNT (peer) < endp)
1575 {
1576 /* Check remaining length check.*/
1577 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1578 {
gdtc29fdba2004-12-09 14:46:46 +00001579 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001580 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001581 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001582 peer->host,
1583 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001584
1585 bgp_notify_send (peer,
1586 BGP_NOTIFY_UPDATE_ERR,
1587 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1588 return -1;
1589 }
1590
1591 /* Fetch attribute flag and type. */
1592 startp = BGP_INPUT_PNT (peer);
1593 flag = stream_getc (BGP_INPUT (peer));
1594 type = stream_getc (BGP_INPUT (peer));
1595
Paul Jakma370b64a2007-12-22 16:49:52 +00001596 /* Check whether Extended-Length applies and is in bounds */
1597 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1598 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1599 {
1600 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001601 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001602 peer->host,
1603 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1604
1605 bgp_notify_send (peer,
1606 BGP_NOTIFY_UPDATE_ERR,
1607 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1608 return -1;
1609 }
1610
paul718e3742002-12-13 20:15:29 +00001611 /* Check extended attribue length bit. */
1612 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1613 length = stream_getw (BGP_INPUT (peer));
1614 else
1615 length = stream_getc (BGP_INPUT (peer));
1616
1617 /* If any attribute appears more than once in the UPDATE
1618 message, then the Error Subcode is set to Malformed Attribute
1619 List. */
1620
1621 if (CHECK_BITMAP (seen, type))
1622 {
1623 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001624 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001625 peer->host, type);
1626
1627 bgp_notify_send (peer,
1628 BGP_NOTIFY_UPDATE_ERR,
1629 BGP_NOTIFY_UPDATE_MAL_ATTR);
1630 return -1;
1631 }
1632
1633 /* Set type to bitmap to check duplicate attribute. `type' is
1634 unsigned char so it never overflow bitmap range. */
1635
1636 SET_BITMAP (seen, type);
1637
1638 /* Overflow check. */
1639 attr_endp = BGP_INPUT_PNT (peer) + length;
1640
1641 if (attr_endp > endp)
1642 {
1643 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001644 "%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 +00001645 bgp_notify_send (peer,
1646 BGP_NOTIFY_UPDATE_ERR,
1647 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1648 return -1;
1649 }
1650
1651 /* OK check attribute and store it's value. */
1652 switch (type)
1653 {
1654 case BGP_ATTR_ORIGIN:
1655 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1656 break;
1657 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001658 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1659 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001660 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001661 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001662 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1663 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001664 break;
paul718e3742002-12-13 20:15:29 +00001665 case BGP_ATTR_NEXT_HOP:
1666 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1667 break;
1668 case BGP_ATTR_MULTI_EXIT_DISC:
1669 ret = bgp_attr_med (peer, length, attr, flag, startp);
1670 break;
1671 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001672 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001673 break;
1674 case BGP_ATTR_ATOMIC_AGGREGATE:
1675 ret = bgp_attr_atomic (peer, length, attr, flag);
1676 break;
1677 case BGP_ATTR_AGGREGATOR:
1678 ret = bgp_attr_aggregator (peer, length, attr, flag);
1679 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001680 case BGP_ATTR_AS4_AGGREGATOR:
1681 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1682 break;
paul718e3742002-12-13 20:15:29 +00001683 case BGP_ATTR_COMMUNITIES:
1684 ret = bgp_attr_community (peer, length, attr, flag);
1685 break;
1686 case BGP_ATTR_ORIGINATOR_ID:
1687 ret = bgp_attr_originator_id (peer, length, attr, flag);
1688 break;
1689 case BGP_ATTR_CLUSTER_LIST:
1690 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1691 break;
1692 case BGP_ATTR_MP_REACH_NLRI:
1693 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1694 break;
1695 case BGP_ATTR_MP_UNREACH_NLRI:
1696 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1697 break;
1698 case BGP_ATTR_EXT_COMMUNITIES:
1699 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1700 break;
1701 default:
1702 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1703 break;
1704 }
1705
1706 /* If error occured immediately return to the caller. */
1707 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001708 {
1709 zlog (peer->log, LOG_WARNING,
1710 "%s: Attribute %s, parse error",
1711 peer->host,
1712 LOOKUP (attr_str, type));
1713 bgp_notify_send (peer,
1714 BGP_NOTIFY_UPDATE_ERR,
1715 BGP_NOTIFY_UPDATE_MAL_ATTR);
1716 return ret;
1717 }
paul718e3742002-12-13 20:15:29 +00001718
1719 /* Check the fetched length. */
1720 if (BGP_INPUT_PNT (peer) != attr_endp)
1721 {
1722 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001723 "%s: BGP attribute %s, fetch error",
1724 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001725 bgp_notify_send (peer,
1726 BGP_NOTIFY_UPDATE_ERR,
1727 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1728 return -1;
1729 }
1730 }
1731
1732 /* Check final read pointer is same as end pointer. */
1733 if (BGP_INPUT_PNT (peer) != endp)
1734 {
1735 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001736 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001737 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001738 bgp_notify_send (peer,
1739 BGP_NOTIFY_UPDATE_ERR,
1740 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1741 return -1;
1742 }
1743
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001744 /*
1745 * At this place we can see whether we got AS4_PATH and/or
1746 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1747 * We can not do this before we've read all attributes because
1748 * the as4 handling does not say whether AS4_PATH has to be sent
1749 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1750 * in relationship to AGGREGATOR.
1751 * So, to be defensive, we are not relying on any order and read
1752 * all attributes first, including these 32bit ones, and now,
1753 * afterwards, we look what and if something is to be done for as4.
1754 */
1755 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1756 as4_aggregator, &as4_aggregator_addr))
1757 return -1;
1758
1759 /* At this stage, we have done all fiddling with as4, and the
1760 * resulting info is in attr->aggregator resp. attr->aspath
1761 * so we can chuck as4_aggregator and as4_path alltogether in
1762 * order to save memory
1763 */
1764 if ( as4_path )
1765 {
1766 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1767 as4_path = NULL;
1768 /* The flag that we got this is still there, but that does not
1769 * do any trouble
1770 */
1771 }
1772 /*
1773 * The "rest" of the code does nothing with as4_aggregator.
1774 * there is no memory attached specifically which is not part
1775 * of the attr.
1776 * so ignoring just means do nothing.
1777 */
1778 /*
1779 * Finally do the checks on the aspath we did not do yet
1780 * because we waited for a potentially synthesized aspath.
1781 */
1782 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1783 {
1784 ret = bgp_attr_aspath_check( peer, attr );
1785 if ( ret < 0 )
1786 return ret;
1787 }
1788
paul718e3742002-12-13 20:15:29 +00001789 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001790 if (attr->extra && attr->extra->transit)
1791 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001792
1793 return 0;
1794}
1795
1796/* Well-known attribute check. */
1797int
1798bgp_attr_check (struct peer *peer, struct attr *attr)
1799{
1800 u_char type = 0;
1801
1802 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1803 type = BGP_ATTR_ORIGIN;
1804
1805 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1806 type = BGP_ATTR_AS_PATH;
1807
1808 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1809 type = BGP_ATTR_NEXT_HOP;
1810
1811 if (peer_sort (peer) == BGP_PEER_IBGP
1812 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1813 type = BGP_ATTR_LOCAL_PREF;
1814
1815 if (type)
1816 {
1817 zlog (peer->log, LOG_WARNING,
1818 "%s Missing well-known attribute %d.",
1819 peer->host, type);
1820 bgp_notify_send_with_data (peer,
1821 BGP_NOTIFY_UPDATE_ERR,
1822 BGP_NOTIFY_UPDATE_MISS_ATTR,
1823 &type, 1);
1824 return -1;
1825 }
1826 return 0;
1827}
1828
1829int stream_put_prefix (struct stream *, struct prefix *);
1830
1831/* Make attribute packet. */
1832bgp_size_t
1833bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1834 struct stream *s, struct attr *attr, struct prefix *p,
1835 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001836 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001837{
paulfe69a502005-09-10 16:55:02 +00001838 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001839 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001840 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001841 int send_as4_path = 0;
1842 int send_as4_aggregator = 0;
1843 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001844
1845 if (! bgp)
1846 bgp = bgp_get_default ();
1847
1848 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001849 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001850
1851 /* Origin attribute. */
1852 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1853 stream_putc (s, BGP_ATTR_ORIGIN);
1854 stream_putc (s, 1);
1855 stream_putc (s, attr->origin);
1856
1857 /* AS path attribute. */
1858
1859 /* If remote-peer is EBGP */
1860 if (peer_sort (peer) == BGP_PEER_EBGP
1861 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001862 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001863 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001864 {
1865 aspath = aspath_dup (attr->aspath);
1866
1867 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1868 {
1869 /* Strip the confed info, and then stuff our path CONFED_ID
1870 on the front */
1871 aspath = aspath_delete_confed_seq (aspath);
1872 aspath = aspath_add_seq (aspath, bgp->confed_id);
1873 }
1874 else
1875 {
1876 aspath = aspath_add_seq (aspath, peer->local_as);
1877 if (peer->change_local_as)
1878 aspath = aspath_add_seq (aspath, peer->change_local_as);
1879 }
1880 }
1881 else if (peer_sort (peer) == BGP_PEER_CONFED)
1882 {
1883 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1884 aspath = aspath_dup (attr->aspath);
1885 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1886 }
1887 else
1888 aspath = attr->aspath;
1889
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001890 /* If peer is not AS4 capable, then:
1891 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1892 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1893 * types are in it (i.e. exclude them if they are there)
1894 * AND do this only if there is at least one asnum > 65535 in the path!
1895 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1896 * all ASnums > 65535 to BGP_AS_TRANS
1897 */
paul718e3742002-12-13 20:15:29 +00001898
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001899 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1900 stream_putc (s, BGP_ATTR_AS_PATH);
1901 aspath_sizep = stream_get_endp (s);
1902 stream_putw (s, 0);
1903 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1904
1905 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1906 * in the path
1907 */
1908 if (!use32bit && aspath_has_as4 (aspath))
1909 send_as4_path = 1; /* we'll do this later, at the correct place */
1910
paul718e3742002-12-13 20:15:29 +00001911 /* Nexthop attribute. */
1912 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1913 {
1914 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1915 stream_putc (s, BGP_ATTR_NEXT_HOP);
1916 stream_putc (s, 4);
1917 if (safi == SAFI_MPLS_VPN)
1918 {
1919 if (attr->nexthop.s_addr == 0)
1920 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1921 else
1922 stream_put_ipv4 (s, attr->nexthop.s_addr);
1923 }
1924 else
1925 stream_put_ipv4 (s, attr->nexthop.s_addr);
1926 }
1927
1928 /* MED attribute. */
1929 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1930 {
1931 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1932 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1933 stream_putc (s, 4);
1934 stream_putl (s, attr->med);
1935 }
1936
1937 /* Local preference. */
1938 if (peer_sort (peer) == BGP_PEER_IBGP ||
1939 peer_sort (peer) == BGP_PEER_CONFED)
1940 {
1941 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1942 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1943 stream_putc (s, 4);
1944 stream_putl (s, attr->local_pref);
1945 }
1946
1947 /* Atomic aggregate. */
1948 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1949 {
1950 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1951 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1952 stream_putc (s, 0);
1953 }
1954
1955 /* Aggregator. */
1956 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1957 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001958 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001959
1960 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001961 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1962 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001963
1964 if (use32bit)
1965 {
1966 /* AS4 capable peer */
1967 stream_putc (s, 8);
1968 stream_putl (s, attr->extra->aggregator_as);
1969 }
1970 else
1971 {
1972 /* 2-byte AS peer */
1973 stream_putc (s, 6);
1974
1975 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1976 if ( attr->extra->aggregator_as > 65535 )
1977 {
1978 stream_putw (s, BGP_AS_TRANS);
1979
1980 /* we have to send AS4_AGGREGATOR, too.
1981 * we'll do that later in order to send attributes in ascending
1982 * order.
1983 */
1984 send_as4_aggregator = 1;
1985 }
1986 else
1987 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1988 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001989 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001990 }
1991
1992 /* Community attribute. */
1993 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1994 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1995 {
1996 if (attr->community->size * 4 > 255)
1997 {
1998 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1999 stream_putc (s, BGP_ATTR_COMMUNITIES);
2000 stream_putw (s, attr->community->size * 4);
2001 }
2002 else
2003 {
2004 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2005 stream_putc (s, BGP_ATTR_COMMUNITIES);
2006 stream_putc (s, attr->community->size * 4);
2007 }
2008 stream_put (s, attr->community->val, attr->community->size * 4);
2009 }
2010
2011 /* Route Reflector. */
2012 if (peer_sort (peer) == BGP_PEER_IBGP
2013 && from
2014 && peer_sort (from) == BGP_PEER_IBGP)
2015 {
2016 /* Originator ID. */
2017 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2018 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2019 stream_putc (s, 4);
2020
2021 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002022 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002023 else
2024 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002025
2026 /* Cluster list. */
2027 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2028 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2029
Paul Jakma9eda90c2007-08-30 13:36:17 +00002030 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002031 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002032 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002033 /* If this peer configuration's parent BGP has cluster_id. */
2034 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2035 stream_put_in_addr (s, &bgp->cluster_id);
2036 else
2037 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002038 stream_put (s, attr->extra->cluster->list,
2039 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002040 }
2041 else
2042 {
2043 stream_putc (s, 4);
2044 /* If this peer configuration's parent BGP has cluster_id. */
2045 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2046 stream_put_in_addr (s, &bgp->cluster_id);
2047 else
2048 stream_put_in_addr (s, &bgp->router_id);
2049 }
2050 }
2051
2052#ifdef HAVE_IPV6
2053 /* If p is IPv6 address put it into attribute. */
2054 if (p->family == AF_INET6)
2055 {
2056 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002057 struct attr_extra *attre = attr->extra;
2058
2059 assert (attr->extra);
2060
paul718e3742002-12-13 20:15:29 +00002061 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2062 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002063 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002064 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002065 stream_putw (s, AFI_IP6); /* AFI */
2066 stream_putc (s, safi); /* SAFI */
2067
Paul Jakmafb982c22007-05-04 20:15:47 +00002068 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002069
Paul Jakmafb982c22007-05-04 20:15:47 +00002070 if (attre->mp_nexthop_len == 16)
2071 stream_put (s, &attre->mp_nexthop_global, 16);
2072 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002073 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002074 stream_put (s, &attre->mp_nexthop_global, 16);
2075 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002076 }
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#endif /* HAVE_IPV6 */
2088
2089 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2090 {
2091 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002092
2093 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2094 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002095 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002096 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002097 stream_putw (s, AFI_IP); /* AFI */
2098 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2099
2100 stream_putc (s, 4);
2101 stream_put_ipv4 (s, attr->nexthop.s_addr);
2102
2103 /* SNPA */
2104 stream_putc (s, 0);
2105
paul718e3742002-12-13 20:15:29 +00002106 /* Prefix write. */
2107 stream_put_prefix (s, p);
2108
2109 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002110 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002111 }
2112
2113 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2114 {
2115 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002116
2117 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2118 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002119 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002120 stream_putc (s, 0); /* Length of this attribute. */
2121 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002122 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002123
2124 stream_putc (s, 12);
2125 stream_putl (s, 0);
2126 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002127 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002128
2129 /* SNPA */
2130 stream_putc (s, 0);
2131
paul718e3742002-12-13 20:15:29 +00002132 /* Tag, RD, Prefix write. */
2133 stream_putc (s, p->prefixlen + 88);
2134 stream_put (s, tag, 3);
2135 stream_put (s, prd->val, 8);
2136 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2137
2138 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002139 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002140 }
2141
2142 /* Extended Communities attribute. */
2143 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2144 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2145 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 struct attr_extra *attre = attr->extra;
2147
2148 assert (attre);
2149
2150 if (peer_sort (peer) == BGP_PEER_IBGP
2151 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002152 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002153 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002154 {
2155 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2156 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002157 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002158 }
2159 else
2160 {
2161 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2162 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002163 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002164 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002165 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002166 }
2167 else
2168 {
paul5228ad22004-06-04 17:58:18 +00002169 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002170 int tbit;
2171 int ecom_tr_size = 0;
2172 int i;
2173
Paul Jakmafb982c22007-05-04 20:15:47 +00002174 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002175 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002176 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002177 tbit = *pnt;
2178
2179 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2180 continue;
2181
2182 ecom_tr_size++;
2183 }
2184
2185 if (ecom_tr_size)
2186 {
2187 if (ecom_tr_size * 8 > 255)
2188 {
2189 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2190 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2191 stream_putw (s, ecom_tr_size * 8);
2192 }
2193 else
2194 {
2195 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2196 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2197 stream_putc (s, ecom_tr_size * 8);
2198 }
2199
Paul Jakmafb982c22007-05-04 20:15:47 +00002200 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002201 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002202 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002203 tbit = *pnt;
2204
2205 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2206 continue;
2207
2208 stream_put (s, pnt, 8);
2209 }
2210 }
paul718e3742002-12-13 20:15:29 +00002211 }
paul718e3742002-12-13 20:15:29 +00002212 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002213
2214 if ( send_as4_path )
2215 {
2216 /* If the peer is NOT As4 capable, AND */
2217 /* there are ASnums > 65535 in path THEN
2218 * give out AS4_PATH */
2219
2220 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2221 * path segments!
2222 * Hm, I wonder... confederation things *should* only be at
2223 * the beginning of an aspath, right? Then we should use
2224 * aspath_delete_confed_seq for this, because it is already
2225 * there! (JK)
2226 * Folks, talk to me: what is reasonable here!?
2227 */
2228 aspath = aspath_delete_confed_seq (aspath);
2229
2230 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2231 stream_putc (s, BGP_ATTR_AS4_PATH);
2232 aspath_sizep = stream_get_endp (s);
2233 stream_putw (s, 0);
2234 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2235 }
2236
2237 if (aspath != attr->aspath)
2238 aspath_free (aspath);
2239
2240 if ( send_as4_aggregator )
2241 {
2242 assert (attr->extra);
2243
2244 /* send AS4_AGGREGATOR, at this place */
2245 /* this section of code moved here in order to ensure the correct
2246 * *ascending* order of attributes
2247 */
2248 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2249 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2250 stream_putc (s, 8);
2251 stream_putl (s, attr->extra->aggregator_as);
2252 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2253 }
Paul Jakma41367172007-08-06 15:24:51 +00002254
paul718e3742002-12-13 20:15:29 +00002255 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002256 if (attr->extra && attr->extra->transit)
2257 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002258
2259 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002260 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002261}
2262
2263bgp_size_t
2264bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2265 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002266 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002267{
2268 unsigned long cp;
2269 unsigned long attrlen_pnt;
2270 bgp_size_t size;
2271
paul9985f832005-02-09 15:51:56 +00002272 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002273
2274 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2275 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2276
paul9985f832005-02-09 15:51:56 +00002277 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002278 stream_putc (s, 0); /* Length of this attribute. */
2279
2280 stream_putw (s, family2afi (p->family));
2281
2282 if (safi == SAFI_MPLS_VPN)
2283 {
2284 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002285 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002286
2287 /* prefix. */
2288 stream_putc (s, p->prefixlen + 88);
2289 stream_put (s, tag, 3);
2290 stream_put (s, prd->val, 8);
2291 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2292 }
2293 else
2294 {
2295 /* SAFI */
2296 stream_putc (s, safi);
2297
2298 /* prefix */
2299 stream_put_prefix (s, p);
2300 }
2301
2302 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002303 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002304 stream_putc_at (s, attrlen_pnt, size);
2305
paul9985f832005-02-09 15:51:56 +00002306 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002307}
2308
2309/* Initialization of attribute. */
2310void
paulfe69a502005-09-10 16:55:02 +00002311bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002312{
paul718e3742002-12-13 20:15:29 +00002313 aspath_init ();
2314 attrhash_init ();
2315 community_init ();
2316 ecommunity_init ();
2317 cluster_init ();
2318 transit_init ();
2319}
2320
Chris Caputo228da422009-07-18 05:44:03 +00002321void
2322bgp_attr_finish (void)
2323{
2324 aspath_finish ();
2325 attrhash_finish ();
2326 community_finish ();
2327 ecommunity_finish ();
2328 cluster_finish ();
2329 transit_finish ();
2330}
2331
paul718e3742002-12-13 20:15:29 +00002332/* Make attribute packet. */
2333void
paula3845922003-10-18 01:30:50 +00002334bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2335 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002336{
2337 unsigned long cp;
2338 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002339 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002340 struct aspath *aspath;
2341
2342 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002343 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002344
2345 /* Place holder of length. */
2346 stream_putw (s, 0);
2347
2348 /* Origin attribute. */
2349 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2350 stream_putc (s, BGP_ATTR_ORIGIN);
2351 stream_putc (s, 1);
2352 stream_putc (s, attr->origin);
2353
2354 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002355
2356 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2357 stream_putc (s, BGP_ATTR_AS_PATH);
2358 aspath_lenp = stream_get_endp (s);
2359 stream_putw (s, 0);
2360
2361 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002362
2363 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002364 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2365 if(prefix != NULL
2366#ifdef HAVE_IPV6
2367 && prefix->family != AF_INET6
2368#endif /* HAVE_IPV6 */
2369 )
2370 {
2371 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2372 stream_putc (s, BGP_ATTR_NEXT_HOP);
2373 stream_putc (s, 4);
2374 stream_put_ipv4 (s, attr->nexthop.s_addr);
2375 }
paul718e3742002-12-13 20:15:29 +00002376
2377 /* MED attribute. */
2378 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2379 {
2380 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2381 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2382 stream_putc (s, 4);
2383 stream_putl (s, attr->med);
2384 }
2385
2386 /* Local preference. */
2387 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2388 {
2389 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2390 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2391 stream_putc (s, 4);
2392 stream_putl (s, attr->local_pref);
2393 }
2394
2395 /* Atomic aggregate. */
2396 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2397 {
2398 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2399 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2400 stream_putc (s, 0);
2401 }
2402
2403 /* Aggregator. */
2404 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2405 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002406 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002407 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2408 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002409 stream_putc (s, 8);
2410 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002412 }
2413
2414 /* Community attribute. */
2415 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2416 {
2417 if (attr->community->size * 4 > 255)
2418 {
2419 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2420 stream_putc (s, BGP_ATTR_COMMUNITIES);
2421 stream_putw (s, attr->community->size * 4);
2422 }
2423 else
2424 {
2425 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2426 stream_putc (s, BGP_ATTR_COMMUNITIES);
2427 stream_putc (s, attr->community->size * 4);
2428 }
2429 stream_put (s, attr->community->val, attr->community->size * 4);
2430 }
2431
paula3845922003-10-18 01:30:50 +00002432#ifdef HAVE_IPV6
2433 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002434 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2435 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002436 {
2437 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002438 struct attr_extra *attre = attr->extra;
2439
paula3845922003-10-18 01:30:50 +00002440 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2441 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002442 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002443
2444 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002445 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002446 stream_putw(s, AFI_IP6); /* AFI */
2447 stream_putc(s, SAFI_UNICAST); /* SAFI */
2448
2449 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002450 stream_putc(s, attre->mp_nexthop_len);
2451 stream_put(s, &attre->mp_nexthop_global, 16);
2452 if (attre->mp_nexthop_len == 32)
2453 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002454
2455 /* SNPA */
2456 stream_putc(s, 0);
2457
2458 /* Prefix */
2459 stream_put_prefix(s, prefix);
2460
2461 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002462 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002463 }
2464#endif /* HAVE_IPV6 */
2465
paul718e3742002-12-13 20:15:29 +00002466 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002467 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002468 stream_putw_at (s, cp, len);
2469}