blob: 5839d3fe0e888e99759bbad076c6636f208d6d17 [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. */
Paul Jakma6e4ab122007-04-10 19:36:48 +000042static 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};
Paul Jakma6e4ab122007-04-10 19:36:48 +000064int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
66struct hash *cluster_hash;
67
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
paul94f2b392005-06-28 12:44:16 +0000151static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000152cluster_dup (struct cluster_list *cluster)
153{
154 struct cluster_list *new;
155
Stephen Hemminger393deb92008-08-18 14:13:29 -0700156 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000157 new->length = cluster->length;
158
159 if (cluster->length)
160 {
161 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
162 memcpy (new->list, cluster->list, cluster->length);
163 }
164 else
165 new->list = NULL;
166
167 return new;
168}
169
paul94f2b392005-06-28 12:44:16 +0000170static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000171cluster_intern (struct cluster_list *cluster)
172{
173 struct cluster_list *find;
174
175 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
176 find->refcnt++;
177
178 return find;
179}
180
181void
182cluster_unintern (struct cluster_list *cluster)
183{
184 struct cluster_list *ret;
185
186 if (cluster->refcnt)
187 cluster->refcnt--;
188
189 if (cluster->refcnt == 0)
190 {
191 ret = hash_release (cluster_hash, cluster);
192 cluster_free (cluster);
193 }
194}
195
paul94f2b392005-06-28 12:44:16 +0000196static void
197cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000198{
199 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
200}
201
202/* Unknown transit attribute. */
203struct hash *transit_hash;
204
paul94f2b392005-06-28 12:44:16 +0000205static void
paul718e3742002-12-13 20:15:29 +0000206transit_free (struct transit *transit)
207{
208 if (transit->val)
209 XFREE (MTYPE_TRANSIT_VAL, transit->val);
210 XFREE (MTYPE_TRANSIT, transit);
211}
212
Paul Jakma923de652007-04-29 18:25:17 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void *
Paul Jakma923de652007-04-29 18:25:17 +0000215transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000216{
217 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000218 return p;
paul718e3742002-12-13 20:15:29 +0000219}
220
paul94f2b392005-06-28 12:44:16 +0000221static struct transit *
paul718e3742002-12-13 20:15:29 +0000222transit_intern (struct transit *transit)
223{
224 struct transit *find;
225
226 find = hash_get (transit_hash, transit, transit_hash_alloc);
227 if (find != transit)
228 transit_free (transit);
229 find->refcnt++;
230
231 return find;
232}
233
234void
235transit_unintern (struct transit *transit)
236{
237 struct transit *ret;
238
239 if (transit->refcnt)
240 transit->refcnt--;
241
242 if (transit->refcnt == 0)
243 {
244 ret = hash_release (transit_hash, transit);
245 transit_free (transit);
246 }
247}
248
paul94f2b392005-06-28 12:44:16 +0000249static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000250transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000251{
Paul Jakma923de652007-04-29 18:25:17 +0000252 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000253 unsigned int key = 0;
254 int length;
255 caddr_t pnt;
256
257 length = transit->length;
258 pnt = (caddr_t) transit->val;
259
260 while (length)
261 key += pnt[--length];
262
263 return key;
264}
265
paul94f2b392005-06-28 12:44:16 +0000266static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100267transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000268{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100269 const struct transit * transit1 = p1;
270 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000271
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100272 return (transit1->length == transit2->length &&
273 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000274}
275
paul94f2b392005-06-28 12:44:16 +0000276static void
paul718e3742002-12-13 20:15:29 +0000277transit_init ()
278{
279 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
280}
281
282/* Attribute hash routines. */
paul718e3742002-12-13 20:15:29 +0000283struct hash *attrhash;
284
Paul Jakmafb982c22007-05-04 20:15:47 +0000285static struct attr_extra *
286bgp_attr_extra_new (void)
287{
288 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
289}
290
291void
292bgp_attr_extra_free (struct attr *attr)
293{
294 if (attr->extra)
295 {
296 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
297 attr->extra = NULL;
298 }
299}
300
301struct attr_extra *
302bgp_attr_extra_get (struct attr *attr)
303{
304 if (!attr->extra)
305 attr->extra = bgp_attr_extra_new();
306 return attr->extra;
307}
308
309/* Shallow copy of an attribute
310 * Though, not so shallow that it doesn't copy the contents
311 * of the attr_extra pointed to by 'extra'
312 */
313void
314bgp_attr_dup (struct attr *new, struct attr *orig)
315{
316 *new = *orig;
317 if (orig->extra)
318 {
319 new->extra = bgp_attr_extra_new();
320 *new->extra = *orig->extra;
321 }
322}
323
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000324unsigned long int
325attr_count (void)
326{
327 return attrhash->count;
328}
329
330unsigned long int
331attr_unknown_count (void)
332{
333 return transit_hash->count;
334}
335
paul718e3742002-12-13 20:15:29 +0000336unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000337attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000338{
Paul Jakma923de652007-04-29 18:25:17 +0000339 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000340 unsigned int key = 0;
341
342 key += attr->origin;
343 key += attr->nexthop.s_addr;
344 key += attr->med;
345 key += attr->local_pref;
Paul Jakma41367172007-08-06 15:24:51 +0000346 if (attr->pathlimit.as)
347 {
348 key += attr->pathlimit.ttl;
349 key += attr->pathlimit.as;
350 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000351
352 if (attr->extra)
353 {
354 key += attr->extra->aggregator_as;
355 key += attr->extra->aggregator_addr.s_addr;
356 key += attr->extra->weight;
357 key += attr->extra->mp_nexthop_global_in.s_addr;
358 }
359
paul718e3742002-12-13 20:15:29 +0000360 if (attr->aspath)
361 key += aspath_key_make (attr->aspath);
362 if (attr->community)
363 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000364
365 if (attr->extra)
366 {
367 if (attr->extra->ecommunity)
368 key += ecommunity_hash_make (attr->extra->ecommunity);
369 if (attr->extra->cluster)
370 key += cluster_hash_key_make (attr->extra->cluster);
371 if (attr->extra->transit)
372 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000373
374#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000375 {
376 int i;
377
378 key += attr->extra->mp_nexthop_len;
379 for (i = 0; i < 16; i++)
380 key += attr->extra->mp_nexthop_global.s6_addr[i];
381 for (i = 0; i < 16; i++)
382 key += attr->extra->mp_nexthop_local.s6_addr[i];
383 }
paul718e3742002-12-13 20:15:29 +0000384#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000385 }
paul718e3742002-12-13 20:15:29 +0000386
387 return key;
388}
389
390int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100391attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000392{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100393 const struct attr * attr1 = p1;
394 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000395
paul718e3742002-12-13 20:15:29 +0000396 if (attr1->flag == attr2->flag
397 && attr1->origin == attr2->origin
398 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000399 && attr1->aspath == attr2->aspath
400 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000401 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000402 && attr1->local_pref == attr2->local_pref
403 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
404 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000405 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100406 const struct attr_extra *ae1 = attr1->extra;
407 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000408
409 if (ae1 && ae2
410 && ae1->aggregator_as == ae2->aggregator_as
411 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
412 && ae1->weight == ae2->weight
413#ifdef HAVE_IPV6
414 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
415 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
416 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
417#endif /* HAVE_IPV6 */
418 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
419 && ae1->ecommunity == ae2->ecommunity
420 && ae1->cluster == ae2->cluster
421 && ae1->transit == ae2->transit)
422 return 1;
423 else if (ae1 || ae2)
424 return 0;
425 /* neither attribute has extra attributes, so they're same */
426 return 1;
427 }
paul718e3742002-12-13 20:15:29 +0000428 else
429 return 0;
430}
431
paul94f2b392005-06-28 12:44:16 +0000432static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100433attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000434{
435 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
436}
437
paul94f2b392005-06-28 12:44:16 +0000438static void
paul718e3742002-12-13 20:15:29 +0000439attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
440{
441 struct attr *attr = backet->data;
442
443 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
444 inet_ntoa (attr->nexthop), VTY_NEWLINE);
445}
446
447void
448attr_show_all (struct vty *vty)
449{
450 hash_iterate (attrhash,
451 (void (*)(struct hash_backet *, void *))
452 attr_show_all_iterator,
453 vty);
454}
455
paul94f2b392005-06-28 12:44:16 +0000456static void *
Paul Jakma923de652007-04-29 18:25:17 +0000457bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000458{
Paul Jakma923de652007-04-29 18:25:17 +0000459 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000460 struct attr *attr;
461
462 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
463 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000464 if (val->extra)
465 {
466 attr->extra = bgp_attr_extra_new ();
467 *attr->extra = *val->extra;
468 }
paul718e3742002-12-13 20:15:29 +0000469 attr->refcnt = 0;
470 return attr;
471}
472
473/* Internet argument attribute. */
474struct attr *
475bgp_attr_intern (struct attr *attr)
476{
477 struct attr *find;
478
479 /* Intern referenced strucutre. */
480 if (attr->aspath)
481 {
482 if (! attr->aspath->refcnt)
483 attr->aspath = aspath_intern (attr->aspath);
484 else
485 attr->aspath->refcnt++;
486 }
487 if (attr->community)
488 {
489 if (! attr->community->refcnt)
490 attr->community = community_intern (attr->community);
491 else
492 attr->community->refcnt++;
493 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000494 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000495 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000496 struct attr_extra *attre = attr->extra;
497
498 if (attre->ecommunity)
499 {
500 if (! attre->ecommunity->refcnt)
501 attre->ecommunity = ecommunity_intern (attre->ecommunity);
502 else
503 attre->ecommunity->refcnt++;
504 }
505 if (attre->cluster)
506 {
507 if (! attre->cluster->refcnt)
508 attre->cluster = cluster_intern (attre->cluster);
509 else
510 attre->cluster->refcnt++;
511 }
512 if (attre->transit)
513 {
514 if (! attre->transit->refcnt)
515 attre->transit = transit_intern (attre->transit);
516 else
517 attre->transit->refcnt++;
518 }
paul718e3742002-12-13 20:15:29 +0000519 }
520
521 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
522 find->refcnt++;
523
524 return find;
525}
526
Paul Jakma03e214c2007-04-29 18:31:07 +0000527
paul718e3742002-12-13 20:15:29 +0000528/* Make network statement's attribute. */
529struct attr *
530bgp_attr_default_set (struct attr *attr, u_char origin)
531{
532 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000533 bgp_attr_extra_get (attr);
534
paul718e3742002-12-13 20:15:29 +0000535 attr->origin = origin;
536 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
537 attr->aspath = aspath_empty ();
538 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000539 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000540 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
541#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000542 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000543#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000544
paul718e3742002-12-13 20:15:29 +0000545 return attr;
546}
547
Paul Jakma03e214c2007-04-29 18:31:07 +0000548
paul718e3742002-12-13 20:15:29 +0000549/* Make network statement's attribute. */
550struct attr *
551bgp_attr_default_intern (u_char origin)
552{
553 struct attr attr;
554 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 struct attr_extra *attre;
556
557 memset (&attr, 0, sizeof (struct attr));
558 attre = bgp_attr_extra_get (&attr);
559
Paul Jakma03e214c2007-04-29 18:31:07 +0000560 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000561
562 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000563 bgp_attr_extra_free (&attr);
564
paul718e3742002-12-13 20:15:29 +0000565 aspath_unintern (new->aspath);
566 return new;
567}
568
569struct attr *
570bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
571 struct aspath *aspath,
572 struct community *community, int as_set)
573{
574 struct attr attr;
575 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000576 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000577
578 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 attre = bgp_attr_extra_get (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 /* Origin attribute. */
582 attr.origin = origin;
583 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
584
585 /* AS path attribute. */
586 if (aspath)
587 attr.aspath = aspath_intern (aspath);
588 else
589 attr.aspath = aspath_empty ();
590 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
591
592 /* Next hop attribute. */
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
594
595 if (community)
596 {
597 attr.community = community;
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
599 }
600
Paul Jakmafb982c22007-05-04 20:15:47 +0000601 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000602#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000603 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000604#endif
605 if (! as_set)
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
608 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000609 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000610 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000611 attre->aggregator_as = bgp->as;
612 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000613
614 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 bgp_attr_extra_free (&attr);
616
paul718e3742002-12-13 20:15:29 +0000617 aspath_unintern (new->aspath);
618 return new;
619}
620
621/* Free bgp attribute and aspath. */
622void
623bgp_attr_unintern (struct attr *attr)
624{
625 struct attr *ret;
626 struct aspath *aspath;
627 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000628 struct ecommunity *ecommunity = NULL;
629 struct cluster_list *cluster = NULL;
630 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000631
632 /* Decrement attribute reference. */
633 attr->refcnt--;
634 aspath = attr->aspath;
635 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000636 if (attr->extra)
637 {
638 ecommunity = attr->extra->ecommunity;
639 cluster = attr->extra->cluster;
640 transit = attr->extra->transit;
641 }
paul718e3742002-12-13 20:15:29 +0000642
643 /* If reference becomes zero then free attribute object. */
644 if (attr->refcnt == 0)
645 {
646 ret = hash_release (attrhash, attr);
647 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000648 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000649 XFREE (MTYPE_ATTR, attr);
650 }
651
652 /* aspath refcount shoud be decrement. */
653 if (aspath)
654 aspath_unintern (aspath);
655 if (community)
656 community_unintern (community);
657 if (ecommunity)
658 ecommunity_unintern (ecommunity);
659 if (cluster)
660 cluster_unintern (cluster);
661 if (transit)
662 transit_unintern (transit);
663}
664
665void
666bgp_attr_flush (struct attr *attr)
667{
668 if (attr->aspath && ! attr->aspath->refcnt)
669 aspath_free (attr->aspath);
670 if (attr->community && ! attr->community->refcnt)
671 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000672 if (attr->extra)
673 {
674 struct attr_extra *attre = attr->extra;
675 if (attre->ecommunity && ! attre->ecommunity->refcnt)
676 ecommunity_free (attre->ecommunity);
677 if (attre->cluster && ! attre->cluster->refcnt)
678 cluster_free (attre->cluster);
679 if (attre->transit && ! attre->transit->refcnt)
680 transit_free (attre->transit);
681 }
paul718e3742002-12-13 20:15:29 +0000682}
683
Paul Jakma41367172007-08-06 15:24:51 +0000684/* Parse AS_PATHLIMIT attribute in an UPDATE */
685static int
686bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
687 struct attr *attr, u_char flag, u_char *startp)
688{
689 bgp_size_t total;
690
691 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
692
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000693 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
694 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
Paul Jakma41367172007-08-06 15:24:51 +0000695 {
696 zlog (peer->log, LOG_ERR,
697 "AS-Pathlimit attribute flag isn't transitive %d", flag);
698 bgp_notify_send_with_data (peer,
699 BGP_NOTIFY_UPDATE_ERR,
700 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
701 startp, total);
702 return -1;
703 }
704
705 if (length != 5)
706 {
707 zlog (peer->log, LOG_ERR,
708 "AS-Pathlimit length, %u, is not 5", length);
709 bgp_notify_send_with_data (peer,
710 BGP_NOTIFY_UPDATE_ERR,
711 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
712 startp, total);
713 return -1;
714 }
715
716 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
717 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
718 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
719 return 0;
720}
paul718e3742002-12-13 20:15:29 +0000721/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000722static int
paul718e3742002-12-13 20:15:29 +0000723bgp_attr_origin (struct peer *peer, bgp_size_t length,
724 struct attr *attr, u_char flag, u_char *startp)
725{
726 bgp_size_t total;
727
728 /* total is entire attribute length include Attribute Flags (1),
729 Attribute Type code (1) and Attribute length (1 or 2). */
730 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
731
732 /* If any recognized attribute has Attribute Flags that conflict
733 with the Attribute Type Code, then the Error Subcode is set to
734 Attribute Flags Error. The Data field contains the erroneous
735 attribute (type, length and value). */
736 if (flag != BGP_ATTR_FLAG_TRANS)
737 {
738 zlog (peer->log, LOG_ERR,
739 "Origin attribute flag isn't transitive %d", flag);
740 bgp_notify_send_with_data (peer,
741 BGP_NOTIFY_UPDATE_ERR,
742 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
743 startp, total);
744 return -1;
745 }
746
747 /* If any recognized attribute has Attribute Length that conflicts
748 with the expected length (based on the attribute type code), then
749 the Error Subcode is set to Attribute Length Error. The Data
750 field contains the erroneous attribute (type, length and
751 value). */
752 if (length != 1)
753 {
754 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
755 length);
756 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
757 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
758 startp, total);
759 return -1;
760 }
761
762 /* Fetch origin attribute. */
763 attr->origin = stream_getc (BGP_INPUT (peer));
764
765 /* If the ORIGIN attribute has an undefined value, then the Error
766 Subcode is set to Invalid Origin Attribute. The Data field
767 contains the unrecognized attribute (type, length and value). */
768 if ((attr->origin != BGP_ORIGIN_IGP)
769 && (attr->origin != BGP_ORIGIN_EGP)
770 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
771 {
772 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
773 attr->origin);
774
775 bgp_notify_send_with_data (peer,
776 BGP_NOTIFY_UPDATE_ERR,
777 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
778 startp, total);
779 return -1;
780 }
781
782 /* Set oring attribute flag. */
783 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
784
785 return 0;
786}
787
788/* Parse AS path information. This function is wrapper of
789 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000790static int
paul718e3742002-12-13 20:15:29 +0000791bgp_attr_aspath (struct peer *peer, bgp_size_t length,
792 struct attr *attr, u_char flag, u_char *startp)
793{
paul718e3742002-12-13 20:15:29 +0000794 bgp_size_t total;
795
796 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
797
798 /* Flag check. */
799 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
800 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
801 {
802 zlog (peer->log, LOG_ERR,
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000803 "As-Path attribute flag isn't transitive %d", flag);
paul718e3742002-12-13 20:15:29 +0000804 bgp_notify_send_with_data (peer,
805 BGP_NOTIFY_UPDATE_ERR,
806 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
807 startp, total);
808 return -1;
809 }
810
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000811 /*
812 * peer with AS4 => will get 4Byte ASnums
813 * otherwise, will get 16 Bit
814 */
815 attr->aspath = aspath_parse (peer->ibuf, length,
816 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
817
paul718e3742002-12-13 20:15:29 +0000818 /* In case of IBGP, length will be zero. */
paul718e3742002-12-13 20:15:29 +0000819 if (! attr->aspath)
820 {
821 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
822 bgp_notify_send (peer,
823 BGP_NOTIFY_UPDATE_ERR,
824 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
825 return -1;
826 }
827
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000828 /* Forward pointer. */
829/* stream_forward_getp (peer->ibuf, length);*/
830
831 /* Set aspath attribute flag. */
832 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
833
834 return 0;
835}
836
837static int bgp_attr_aspath_check( struct peer *peer,
838 struct attr *attr)
839{
840 /* These checks were part of bgp_attr_aspath, but with
841 * as4 we should to check aspath things when
842 * aspath synthesizing with as4_path has already taken place.
843 * Otherwise we check ASPATH and use the synthesized thing, and that is
844 * not right.
845 * So do the checks later, i.e. here
846 */
847 struct bgp *bgp = peer->bgp;
848 struct aspath *aspath;
849
paul718e3742002-12-13 20:15:29 +0000850 bgp = peer->bgp;
851
852 /* First AS check for EBGP. */
853 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
854 {
855 if (peer_sort (peer) == BGP_PEER_EBGP
856 && ! aspath_firstas_check (attr->aspath, peer->as))
857 {
858 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400859 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000860 bgp_notify_send (peer,
861 BGP_NOTIFY_UPDATE_ERR,
862 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
863 return -1;
864 }
865 }
866
867 /* local-as prepend */
868 if (peer->change_local_as &&
869 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
870 {
871 aspath = aspath_dup (attr->aspath);
872 aspath = aspath_add_seq (aspath, peer->change_local_as);
873 aspath_unintern (attr->aspath);
874 attr->aspath = aspath_intern (aspath);
875 }
876
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000877 return 0;
878
879}
880
881/* Parse AS4 path information. This function is another wrapper of
882 aspath_parse. */
883static int
884bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
885 struct attr *attr, struct aspath **as4_path)
886{
887 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000888
889 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000890 if (as4_path)
891 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000892
893 return 0;
894}
895
896/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000897static int
paul718e3742002-12-13 20:15:29 +0000898bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
899 struct attr *attr, u_char flag, u_char *startp)
900{
901 bgp_size_t total;
902
903 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
904
905 /* Flag check. */
906 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
907 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
908 {
909 zlog (peer->log, LOG_ERR,
910 "Origin attribute flag isn't transitive %d", flag);
911 bgp_notify_send_with_data (peer,
912 BGP_NOTIFY_UPDATE_ERR,
913 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
914 startp, total);
915 return -1;
916 }
917
918 /* Check nexthop attribute length. */
919 if (length != 4)
920 {
921 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
922 length);
923
924 bgp_notify_send_with_data (peer,
925 BGP_NOTIFY_UPDATE_ERR,
926 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
927 startp, total);
928 return -1;
929 }
930
931 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
932 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
933
934 return 0;
935}
936
937/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000938static int
paul718e3742002-12-13 20:15:29 +0000939bgp_attr_med (struct peer *peer, bgp_size_t length,
940 struct attr *attr, u_char flag, u_char *startp)
941{
942 bgp_size_t total;
943
944 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
945
946 /* Length check. */
947 if (length != 4)
948 {
949 zlog (peer->log, LOG_ERR,
950 "MED attribute length isn't four [%d]", length);
951
952 bgp_notify_send_with_data (peer,
953 BGP_NOTIFY_UPDATE_ERR,
954 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
955 startp, total);
956 return -1;
957 }
958
959 attr->med = stream_getl (peer->ibuf);
960
961 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
962
963 return 0;
964}
965
966/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000967static int
paul718e3742002-12-13 20:15:29 +0000968bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
969 struct attr *attr, u_char flag)
970{
971 /* If it is contained in an UPDATE message that is received from an
972 external peer, then this attribute MUST be ignored by the
973 receiving speaker. */
974 if (peer_sort (peer) == BGP_PEER_EBGP)
975 {
paul9985f832005-02-09 15:51:56 +0000976 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000977 return 0;
978 }
979
980 if (length == 4)
981 attr->local_pref = stream_getl (peer->ibuf);
982 else
983 attr->local_pref = 0;
984
985 /* Set atomic aggregate flag. */
986 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
987
988 return 0;
989}
990
991/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000992static int
paul718e3742002-12-13 20:15:29 +0000993bgp_attr_atomic (struct peer *peer, bgp_size_t length,
994 struct attr *attr, u_char flag)
995{
996 if (length != 0)
997 {
998 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
999
1000 bgp_notify_send (peer,
1001 BGP_NOTIFY_UPDATE_ERR,
1002 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1003 return -1;
1004 }
1005
1006 /* Set atomic aggregate flag. */
1007 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1008
1009 return 0;
1010}
1011
1012/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001013static int
paul718e3742002-12-13 20:15:29 +00001014bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1015 struct attr *attr, u_char flag)
1016{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001017 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001018 struct attr_extra *attre = bgp_attr_extra_get (attr);
1019
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001020 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1021 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1022 wantedlen = 8;
1023
1024 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001025 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001026 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001027
1028 bgp_notify_send (peer,
1029 BGP_NOTIFY_UPDATE_ERR,
1030 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1031 return -1;
1032 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001033
1034 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1035 attre->aggregator_as = stream_getl (peer->ibuf);
1036 else
1037 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001038 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001039
1040 /* Set atomic aggregate flag. */
1041 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1042
1043 return 0;
1044}
1045
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001046/* New Aggregator attribute */
1047static int
1048bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1049 struct attr *attr, as_t *as4_aggregator_as,
1050 struct in_addr *as4_aggregator_addr)
1051{
1052 if (length != 8)
1053 {
1054 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1055
1056 bgp_notify_send (peer,
1057 BGP_NOTIFY_UPDATE_ERR,
1058 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1059 return -1;
1060 }
1061 *as4_aggregator_as = stream_getl (peer->ibuf);
1062 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1063
1064 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1065
1066 return 0;
1067}
1068
1069/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1070 */
1071static int
1072bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1073 struct aspath *as4_path, as_t as4_aggregator,
1074 struct in_addr *as4_aggregator_addr)
1075{
1076 int ignore_as4_path = 0;
1077 struct aspath *newpath;
1078 struct attr_extra *attre = attr->extra;
1079
1080 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1081 {
1082 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1083 * if given.
1084 * It is worth a warning though, because the peer really
1085 * should not send them
1086 */
1087 if (BGP_DEBUG(as4, AS4))
1088 {
1089 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1090 zlog_debug ("[AS4] %s %s AS4_PATH",
1091 peer->host, "AS4 capable peer, yet it sent");
1092
1093 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1094 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1095 peer->host, "AS4 capable peer, yet it sent");
1096 }
1097
1098 return 0;
1099 }
1100
1101 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1102 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1103 {
1104 /* Hu? This is not supposed to happen at all!
1105 * got as4_path and no aspath,
1106 * This should already
1107 * have been handled by 'well known attributes missing'
1108 * But... yeah, paranoia
1109 * Take this as a "malformed attribute"
1110 */
1111 zlog (peer->log, LOG_ERR,
1112 "%s BGP not AS4 capable peer sent AS4_PATH but"
1113 " no AS_PATH, cant do anything here", peer->host);
1114 bgp_notify_send (peer,
1115 BGP_NOTIFY_UPDATE_ERR,
1116 BGP_NOTIFY_UPDATE_MAL_ATTR);
1117 return -1;
1118 }
1119
1120 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1121 * because that may override AS4_PATH
1122 */
1123 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1124 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001125 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1126 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001127 assert (attre);
1128
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001129 /* received both.
1130 * if the as_number in aggregator is not AS_TRANS,
1131 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1132 * and the Aggregator shall be taken as
1133 * info on the aggregating node, and the AS_PATH
1134 * shall be taken as the AS_PATH
1135 * otherwise
1136 * the Aggregator shall be ignored and the
1137 * AS4_AGGREGATOR shall be taken as the
1138 * Aggregating node and the AS_PATH is to be
1139 * constructed "as in all other cases"
1140 */
1141 if ( attre->aggregator_as != BGP_AS_TRANS )
1142 {
1143 /* ignore */
1144 if ( BGP_DEBUG(as4, AS4))
1145 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1146 " send AGGREGATOR != AS_TRANS and"
1147 " AS4_AGGREGATOR, so ignore"
1148 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1149 ignore_as4_path = 1;
1150 }
1151 else
1152 {
1153 /* "New_aggregator shall be taken as aggregator" */
1154 attre->aggregator_as = as4_aggregator;
1155 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1156 }
1157 }
1158 else
1159 {
1160 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1161 * That is bogus - but reading the conditions
1162 * we have to handle AS4_AGGREGATOR as if it were
1163 * AGGREGATOR in that case
1164 */
1165 if ( BGP_DEBUG(as4, AS4))
1166 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1167 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1168 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001169 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001170 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1171 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1172 }
1173 }
1174
1175 /* need to reconcile NEW_AS_PATH and AS_PATH */
1176 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1177 {
1178 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1179 aspath_unintern (attr->aspath);
1180 attr->aspath = aspath_intern (newpath);
1181 }
1182 return 0;
1183}
1184
paul718e3742002-12-13 20:15:29 +00001185/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001186static int
paul718e3742002-12-13 20:15:29 +00001187bgp_attr_community (struct peer *peer, bgp_size_t length,
1188 struct attr *attr, u_char flag)
1189{
1190 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001191 {
1192 attr->community = NULL;
1193 return 0;
1194 }
paul718e3742002-12-13 20:15:29 +00001195 else
1196 {
paul5228ad22004-06-04 17:58:18 +00001197 attr->community =
1198 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001199 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001200 }
1201
1202 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1203
1204 return 0;
1205}
1206
1207/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001208static int
paul718e3742002-12-13 20:15:29 +00001209bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1210 struct attr *attr, u_char flag)
1211{
1212 if (length != 4)
1213 {
1214 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1215
1216 bgp_notify_send (peer,
1217 BGP_NOTIFY_UPDATE_ERR,
1218 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1219 return -1;
1220 }
1221
Paul Jakmafb982c22007-05-04 20:15:47 +00001222 (bgp_attr_extra_get (attr))->originator_id.s_addr
1223 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001224
1225 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1226
1227 return 0;
1228}
1229
1230/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001231static int
paul718e3742002-12-13 20:15:29 +00001232bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1233 struct attr *attr, u_char flag)
1234{
1235 /* Check length. */
1236 if (length % 4)
1237 {
1238 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1239
1240 bgp_notify_send (peer,
1241 BGP_NOTIFY_UPDATE_ERR,
1242 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1243 return -1;
1244 }
1245
Paul Jakmafb982c22007-05-04 20:15:47 +00001246 (bgp_attr_extra_get (attr))->cluster
1247 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001248
paul9985f832005-02-09 15:51:56 +00001249 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001250
1251 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1252
1253 return 0;
1254}
1255
1256/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001257int
paul718e3742002-12-13 20:15:29 +00001258bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1259 struct bgp_nlri *mp_update)
1260{
1261 u_int16_t afi;
1262 u_char safi;
paul718e3742002-12-13 20:15:29 +00001263 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001264 size_t start;
paul718e3742002-12-13 20:15:29 +00001265 int ret;
1266 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001267 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001268
1269 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001270 s = BGP_INPUT(peer);
1271 start = stream_get_getp(s);
1272
1273 /* safe to read statically sized header? */
1274#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001275#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001276 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001277 {
1278 zlog_info ("%s: %s sent invalid length, %lu",
1279 __func__, peer->host, (unsigned long)length);
1280 return -1;
1281 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001282
paul718e3742002-12-13 20:15:29 +00001283 /* Load AFI, SAFI. */
1284 afi = stream_getw (s);
1285 safi = stream_getc (s);
1286
1287 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001288 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001289
Paul Jakma03292802008-06-07 20:37:10 +00001290 if (LEN_LEFT < attre->mp_nexthop_len)
1291 {
1292 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1293 __func__, peer->host, attre->mp_nexthop_len);
1294 return -1;
1295 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001296
paul718e3742002-12-13 20:15:29 +00001297 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001298 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001299 {
1300 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001301 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001302 break;
1303 case 12:
1304 {
1305 u_int32_t rd_high;
1306 u_int32_t rd_low;
1307
1308 rd_high = stream_getl (s);
1309 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001310 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001311 }
1312 break;
1313#ifdef HAVE_IPV6
1314 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001315 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001316 break;
1317 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001318 stream_get (&attre->mp_nexthop_global, s, 16);
1319 stream_get (&attre->mp_nexthop_local, s, 16);
1320 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001321 {
1322 char buf1[INET6_ADDRSTRLEN];
1323 char buf2[INET6_ADDRSTRLEN];
1324
1325 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001326 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 +00001327 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001328 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001329 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001330 buf2, INET6_ADDRSTRLEN));
1331
Paul Jakmafb982c22007-05-04 20:15:47 +00001332 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001333 }
1334 break;
1335#endif /* HAVE_IPV6 */
1336 default:
Paul Jakma03292802008-06-07 20:37:10 +00001337 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1338 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001339 return -1;
paul718e3742002-12-13 20:15:29 +00001340 }
1341
Paul Jakma03292802008-06-07 20:37:10 +00001342 if (!LEN_LEFT)
1343 {
1344 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1345 __func__, peer->host);
1346 return -1;
1347 }
paul718e3742002-12-13 20:15:29 +00001348
Paul Jakma6e4ab122007-04-10 19:36:48 +00001349 {
1350 u_char val;
1351 if ((val = stream_getc (s)))
1352 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1353 peer->host, val);
1354 }
1355
1356 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001357 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001358 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001359 {
1360 zlog_info ("%s: (%s) Failed to read NLRI",
1361 __func__, peer->host);
1362 return -1;
1363 }
paul718e3742002-12-13 20:15:29 +00001364
1365 if (safi != BGP_SAFI_VPNV4)
1366 {
1367 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001368 if (ret < 0)
1369 {
1370 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1371 __func__, peer->host);
1372 return -1;
1373 }
paul718e3742002-12-13 20:15:29 +00001374 }
1375
1376 mp_update->afi = afi;
1377 mp_update->safi = safi;
1378 mp_update->nlri = stream_pnt (s);
1379 mp_update->length = nlri_len;
1380
paul9985f832005-02-09 15:51:56 +00001381 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001382
1383 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001384#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001385}
1386
1387/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001388int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001389bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001390 struct bgp_nlri *mp_withdraw)
1391{
1392 struct stream *s;
1393 u_int16_t afi;
1394 u_char safi;
paul718e3742002-12-13 20:15:29 +00001395 u_int16_t withdraw_len;
1396 int ret;
1397
1398 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001399
1400#define BGP_MP_UNREACH_MIN_SIZE 3
1401 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1402 return -1;
1403
paul718e3742002-12-13 20:15:29 +00001404 afi = stream_getw (s);
1405 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001406
1407 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001408
1409 if (safi != BGP_SAFI_VPNV4)
1410 {
1411 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1412 if (ret < 0)
1413 return -1;
1414 }
1415
1416 mp_withdraw->afi = afi;
1417 mp_withdraw->safi = safi;
1418 mp_withdraw->nlri = stream_pnt (s);
1419 mp_withdraw->length = withdraw_len;
1420
paul9985f832005-02-09 15:51:56 +00001421 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001422
1423 return 0;
1424}
1425
1426/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001427static int
paul718e3742002-12-13 20:15:29 +00001428bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1429 struct attr *attr, u_char flag)
1430{
1431 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001432 {
1433 if (attr->extra)
1434 attr->extra->ecommunity = NULL;
1435 }
paul718e3742002-12-13 20:15:29 +00001436 else
1437 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001438 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001439 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001440 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001441 }
1442 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1443
1444 return 0;
1445}
1446
1447/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001448static int
paul718e3742002-12-13 20:15:29 +00001449bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1450 u_char type, bgp_size_t length, u_char *startp)
1451{
1452 bgp_size_t total;
1453 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001454 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001455
hassof4184462005-02-01 20:13:16 +00001456 if (BGP_DEBUG (normal, NORMAL))
1457 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1458 peer->host, type, length);
1459
paul718e3742002-12-13 20:15:29 +00001460 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001461 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001462 "Unknown attribute type %d length %d is received", type, length);
1463
1464 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001465 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001466
1467 /* Adjest total length to include type and length. */
1468 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1469
1470 /* If any of the mandatory well-known attributes are not recognized,
1471 then the Error Subcode is set to Unrecognized Well-known
1472 Attribute. The Data field contains the unrecognized attribute
1473 (type, length and value). */
1474 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1475 {
1476 /* Adjust startp to do not include flag value. */
1477 bgp_notify_send_with_data (peer,
1478 BGP_NOTIFY_UPDATE_ERR,
1479 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1480 startp, total);
1481 return -1;
1482 }
1483
1484 /* Unrecognized non-transitive optional attributes must be quietly
1485 ignored and not passed along to other BGP peers. */
1486 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1487 return 0;
1488
1489 /* If a path with recognized transitive optional attribute is
1490 accepted and passed along to other BGP peers and the Partial bit
1491 in the Attribute Flags octet is set to 1 by some previous AS, it
1492 is not set back to 0 by the current AS. */
1493 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1494
1495 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001496 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001497 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001498
Paul Jakmafb982c22007-05-04 20:15:47 +00001499 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001500
1501 if (transit->val)
1502 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1503 transit->length + total);
1504 else
1505 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1506
1507 memcpy (transit->val + transit->length, startp, total);
1508 transit->length += total;
1509
1510 return 0;
1511}
1512
1513/* Read attribute of update packet. This function is called from
1514 bgp_update() in bgpd.c. */
1515int
1516bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1517 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1518{
1519 int ret;
1520 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001521 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001522 bgp_size_t length;
1523 u_char *startp, *endp;
1524 u_char *attr_endp;
1525 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001526 /* we need the as4_path only until we have synthesized the as_path with it */
1527 /* same goes for as4_aggregator */
1528 struct aspath *as4_path = NULL;
1529 as_t as4_aggregator = 0;
1530 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001531
1532 /* Initialize bitmap. */
1533 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1534
1535 /* End pointer of BGP attribute. */
1536 endp = BGP_INPUT_PNT (peer) + size;
1537
1538 /* Get attributes to the end of attribute length. */
1539 while (BGP_INPUT_PNT (peer) < endp)
1540 {
1541 /* Check remaining length check.*/
1542 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1543 {
gdtc29fdba2004-12-09 14:46:46 +00001544 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001545 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001546 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001547 peer->host,
1548 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001549
1550 bgp_notify_send (peer,
1551 BGP_NOTIFY_UPDATE_ERR,
1552 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1553 return -1;
1554 }
1555
1556 /* Fetch attribute flag and type. */
1557 startp = BGP_INPUT_PNT (peer);
1558 flag = stream_getc (BGP_INPUT (peer));
1559 type = stream_getc (BGP_INPUT (peer));
1560
Paul Jakma370b64a2007-12-22 16:49:52 +00001561 /* Check whether Extended-Length applies and is in bounds */
1562 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1563 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1564 {
1565 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001566 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001567 peer->host,
1568 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1569
1570 bgp_notify_send (peer,
1571 BGP_NOTIFY_UPDATE_ERR,
1572 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1573 return -1;
1574 }
1575
paul718e3742002-12-13 20:15:29 +00001576 /* Check extended attribue length bit. */
1577 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1578 length = stream_getw (BGP_INPUT (peer));
1579 else
1580 length = stream_getc (BGP_INPUT (peer));
1581
1582 /* If any attribute appears more than once in the UPDATE
1583 message, then the Error Subcode is set to Malformed Attribute
1584 List. */
1585
1586 if (CHECK_BITMAP (seen, type))
1587 {
1588 zlog (peer->log, LOG_WARNING,
1589 "%s error BGP attribute type %d appears twice in a message",
1590 peer->host, type);
1591
1592 bgp_notify_send (peer,
1593 BGP_NOTIFY_UPDATE_ERR,
1594 BGP_NOTIFY_UPDATE_MAL_ATTR);
1595 return -1;
1596 }
1597
1598 /* Set type to bitmap to check duplicate attribute. `type' is
1599 unsigned char so it never overflow bitmap range. */
1600
1601 SET_BITMAP (seen, type);
1602
1603 /* Overflow check. */
1604 attr_endp = BGP_INPUT_PNT (peer) + length;
1605
1606 if (attr_endp > endp)
1607 {
1608 zlog (peer->log, LOG_WARNING,
1609 "%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);
1610 bgp_notify_send (peer,
1611 BGP_NOTIFY_UPDATE_ERR,
1612 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1613 return -1;
1614 }
1615
1616 /* OK check attribute and store it's value. */
1617 switch (type)
1618 {
1619 case BGP_ATTR_ORIGIN:
1620 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1621 break;
1622 case BGP_ATTR_AS_PATH:
1623 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1624 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001625 case BGP_ATTR_AS4_PATH:
1626 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1627 break;
paul718e3742002-12-13 20:15:29 +00001628 case BGP_ATTR_NEXT_HOP:
1629 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1630 break;
1631 case BGP_ATTR_MULTI_EXIT_DISC:
1632 ret = bgp_attr_med (peer, length, attr, flag, startp);
1633 break;
1634 case BGP_ATTR_LOCAL_PREF:
1635 ret = bgp_attr_local_pref (peer, length, attr, flag);
1636 break;
1637 case BGP_ATTR_ATOMIC_AGGREGATE:
1638 ret = bgp_attr_atomic (peer, length, attr, flag);
1639 break;
1640 case BGP_ATTR_AGGREGATOR:
1641 ret = bgp_attr_aggregator (peer, length, attr, flag);
1642 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001643 case BGP_ATTR_AS4_AGGREGATOR:
1644 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1645 break;
paul718e3742002-12-13 20:15:29 +00001646 case BGP_ATTR_COMMUNITIES:
1647 ret = bgp_attr_community (peer, length, attr, flag);
1648 break;
1649 case BGP_ATTR_ORIGINATOR_ID:
1650 ret = bgp_attr_originator_id (peer, length, attr, flag);
1651 break;
1652 case BGP_ATTR_CLUSTER_LIST:
1653 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1654 break;
1655 case BGP_ATTR_MP_REACH_NLRI:
1656 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1657 break;
1658 case BGP_ATTR_MP_UNREACH_NLRI:
1659 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1660 break;
1661 case BGP_ATTR_EXT_COMMUNITIES:
1662 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1663 break;
Paul Jakma41367172007-08-06 15:24:51 +00001664 case BGP_ATTR_AS_PATHLIMIT:
1665 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1666 break;
paul718e3742002-12-13 20:15:29 +00001667 default:
1668 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1669 break;
1670 }
1671
1672 /* If error occured immediately return to the caller. */
1673 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001674 {
1675 zlog (peer->log, LOG_WARNING,
1676 "%s: Attribute %s, parse error",
1677 peer->host,
1678 LOOKUP (attr_str, type));
1679 bgp_notify_send (peer,
1680 BGP_NOTIFY_UPDATE_ERR,
1681 BGP_NOTIFY_UPDATE_MAL_ATTR);
1682 return ret;
1683 }
paul718e3742002-12-13 20:15:29 +00001684
1685 /* Check the fetched length. */
1686 if (BGP_INPUT_PNT (peer) != attr_endp)
1687 {
1688 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001689 "%s: BGP attribute %s, fetch error",
1690 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001691 bgp_notify_send (peer,
1692 BGP_NOTIFY_UPDATE_ERR,
1693 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1694 return -1;
1695 }
1696 }
1697
1698 /* Check final read pointer is same as end pointer. */
1699 if (BGP_INPUT_PNT (peer) != endp)
1700 {
1701 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001702 "%s BGP attribute %s, length mismatch",
1703 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001704 bgp_notify_send (peer,
1705 BGP_NOTIFY_UPDATE_ERR,
1706 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1707 return -1;
1708 }
1709
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001710 /*
1711 * At this place we can see whether we got AS4_PATH and/or
1712 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1713 * We can not do this before we've read all attributes because
1714 * the as4 handling does not say whether AS4_PATH has to be sent
1715 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1716 * in relationship to AGGREGATOR.
1717 * So, to be defensive, we are not relying on any order and read
1718 * all attributes first, including these 32bit ones, and now,
1719 * afterwards, we look what and if something is to be done for as4.
1720 */
1721 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1722 as4_aggregator, &as4_aggregator_addr))
1723 return -1;
1724
1725 /* At this stage, we have done all fiddling with as4, and the
1726 * resulting info is in attr->aggregator resp. attr->aspath
1727 * so we can chuck as4_aggregator and as4_path alltogether in
1728 * order to save memory
1729 */
1730 if ( as4_path )
1731 {
1732 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1733 as4_path = NULL;
1734 /* The flag that we got this is still there, but that does not
1735 * do any trouble
1736 */
1737 }
1738 /*
1739 * The "rest" of the code does nothing with as4_aggregator.
1740 * there is no memory attached specifically which is not part
1741 * of the attr.
1742 * so ignoring just means do nothing.
1743 */
1744 /*
1745 * Finally do the checks on the aspath we did not do yet
1746 * because we waited for a potentially synthesized aspath.
1747 */
1748 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1749 {
1750 ret = bgp_attr_aspath_check( peer, attr );
1751 if ( ret < 0 )
1752 return ret;
1753 }
1754
paul718e3742002-12-13 20:15:29 +00001755 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001756 if (attr->extra && attr->extra->transit)
1757 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001758
1759 return 0;
1760}
1761
1762/* Well-known attribute check. */
1763int
1764bgp_attr_check (struct peer *peer, struct attr *attr)
1765{
1766 u_char type = 0;
1767
1768 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1769 type = BGP_ATTR_ORIGIN;
1770
1771 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1772 type = BGP_ATTR_AS_PATH;
1773
1774 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1775 type = BGP_ATTR_NEXT_HOP;
1776
1777 if (peer_sort (peer) == BGP_PEER_IBGP
1778 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1779 type = BGP_ATTR_LOCAL_PREF;
1780
1781 if (type)
1782 {
1783 zlog (peer->log, LOG_WARNING,
1784 "%s Missing well-known attribute %d.",
1785 peer->host, type);
1786 bgp_notify_send_with_data (peer,
1787 BGP_NOTIFY_UPDATE_ERR,
1788 BGP_NOTIFY_UPDATE_MISS_ATTR,
1789 &type, 1);
1790 return -1;
1791 }
1792 return 0;
1793}
1794
1795int stream_put_prefix (struct stream *, struct prefix *);
1796
1797/* Make attribute packet. */
1798bgp_size_t
1799bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1800 struct stream *s, struct attr *attr, struct prefix *p,
1801 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001802 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001803{
paulfe69a502005-09-10 16:55:02 +00001804 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001805 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001806 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001807 int send_as4_path = 0;
1808 int send_as4_aggregator = 0;
1809 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001810
1811 if (! bgp)
1812 bgp = bgp_get_default ();
1813
1814 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001815 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001816
1817 /* Origin attribute. */
1818 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1819 stream_putc (s, BGP_ATTR_ORIGIN);
1820 stream_putc (s, 1);
1821 stream_putc (s, attr->origin);
1822
1823 /* AS path attribute. */
1824
1825 /* If remote-peer is EBGP */
1826 if (peer_sort (peer) == BGP_PEER_EBGP
1827 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001828 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001829 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001830 {
1831 aspath = aspath_dup (attr->aspath);
1832
1833 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1834 {
1835 /* Strip the confed info, and then stuff our path CONFED_ID
1836 on the front */
1837 aspath = aspath_delete_confed_seq (aspath);
1838 aspath = aspath_add_seq (aspath, bgp->confed_id);
1839 }
1840 else
1841 {
1842 aspath = aspath_add_seq (aspath, peer->local_as);
1843 if (peer->change_local_as)
1844 aspath = aspath_add_seq (aspath, peer->change_local_as);
1845 }
1846 }
1847 else if (peer_sort (peer) == BGP_PEER_CONFED)
1848 {
1849 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1850 aspath = aspath_dup (attr->aspath);
1851 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1852 }
1853 else
1854 aspath = attr->aspath;
1855
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001856 /* If peer is not AS4 capable, then:
1857 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1858 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1859 * types are in it (i.e. exclude them if they are there)
1860 * AND do this only if there is at least one asnum > 65535 in the path!
1861 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1862 * all ASnums > 65535 to BGP_AS_TRANS
1863 */
paul718e3742002-12-13 20:15:29 +00001864
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001865 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1866 stream_putc (s, BGP_ATTR_AS_PATH);
1867 aspath_sizep = stream_get_endp (s);
1868 stream_putw (s, 0);
1869 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1870
1871 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1872 * in the path
1873 */
1874 if (!use32bit && aspath_has_as4 (aspath))
1875 send_as4_path = 1; /* we'll do this later, at the correct place */
1876
paul718e3742002-12-13 20:15:29 +00001877 /* Nexthop attribute. */
1878 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1879 {
1880 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1881 stream_putc (s, BGP_ATTR_NEXT_HOP);
1882 stream_putc (s, 4);
1883 if (safi == SAFI_MPLS_VPN)
1884 {
1885 if (attr->nexthop.s_addr == 0)
1886 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1887 else
1888 stream_put_ipv4 (s, attr->nexthop.s_addr);
1889 }
1890 else
1891 stream_put_ipv4 (s, attr->nexthop.s_addr);
1892 }
1893
1894 /* MED attribute. */
1895 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1896 {
1897 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1898 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1899 stream_putc (s, 4);
1900 stream_putl (s, attr->med);
1901 }
1902
1903 /* Local preference. */
1904 if (peer_sort (peer) == BGP_PEER_IBGP ||
1905 peer_sort (peer) == BGP_PEER_CONFED)
1906 {
1907 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1908 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1909 stream_putc (s, 4);
1910 stream_putl (s, attr->local_pref);
1911 }
1912
1913 /* Atomic aggregate. */
1914 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1915 {
1916 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1917 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1918 stream_putc (s, 0);
1919 }
1920
1921 /* Aggregator. */
1922 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1923 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001924 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001925
1926 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001927 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1928 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001929
1930 if (use32bit)
1931 {
1932 /* AS4 capable peer */
1933 stream_putc (s, 8);
1934 stream_putl (s, attr->extra->aggregator_as);
1935 }
1936 else
1937 {
1938 /* 2-byte AS peer */
1939 stream_putc (s, 6);
1940
1941 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1942 if ( attr->extra->aggregator_as > 65535 )
1943 {
1944 stream_putw (s, BGP_AS_TRANS);
1945
1946 /* we have to send AS4_AGGREGATOR, too.
1947 * we'll do that later in order to send attributes in ascending
1948 * order.
1949 */
1950 send_as4_aggregator = 1;
1951 }
1952 else
1953 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1954 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001955 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001956 }
1957
1958 /* Community attribute. */
1959 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1960 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1961 {
1962 if (attr->community->size * 4 > 255)
1963 {
1964 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1965 stream_putc (s, BGP_ATTR_COMMUNITIES);
1966 stream_putw (s, attr->community->size * 4);
1967 }
1968 else
1969 {
1970 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1971 stream_putc (s, BGP_ATTR_COMMUNITIES);
1972 stream_putc (s, attr->community->size * 4);
1973 }
1974 stream_put (s, attr->community->val, attr->community->size * 4);
1975 }
1976
1977 /* Route Reflector. */
1978 if (peer_sort (peer) == BGP_PEER_IBGP
1979 && from
1980 && peer_sort (from) == BGP_PEER_IBGP)
1981 {
1982 /* Originator ID. */
1983 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1984 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1985 stream_putc (s, 4);
1986
1987 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001988 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001989 else
1990 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001991
1992 /* Cluster list. */
1993 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1994 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1995
Paul Jakma9eda90c2007-08-30 13:36:17 +00001996 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001997 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001998 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001999 /* If this peer configuration's parent BGP has cluster_id. */
2000 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2001 stream_put_in_addr (s, &bgp->cluster_id);
2002 else
2003 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002004 stream_put (s, attr->extra->cluster->list,
2005 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002006 }
2007 else
2008 {
2009 stream_putc (s, 4);
2010 /* If this peer configuration's parent BGP has cluster_id. */
2011 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2012 stream_put_in_addr (s, &bgp->cluster_id);
2013 else
2014 stream_put_in_addr (s, &bgp->router_id);
2015 }
2016 }
2017
2018#ifdef HAVE_IPV6
2019 /* If p is IPv6 address put it into attribute. */
2020 if (p->family == AF_INET6)
2021 {
2022 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002023 struct attr_extra *attre = attr->extra;
2024
2025 assert (attr->extra);
2026
paul718e3742002-12-13 20:15:29 +00002027 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2028 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002029 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002030 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002031 stream_putw (s, AFI_IP6); /* AFI */
2032 stream_putc (s, safi); /* SAFI */
2033
Paul Jakmafb982c22007-05-04 20:15:47 +00002034 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002035
Paul Jakmafb982c22007-05-04 20:15:47 +00002036 if (attre->mp_nexthop_len == 16)
2037 stream_put (s, &attre->mp_nexthop_global, 16);
2038 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002039 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002040 stream_put (s, &attre->mp_nexthop_global, 16);
2041 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002042 }
2043
2044 /* SNPA */
2045 stream_putc (s, 0);
2046
paul718e3742002-12-13 20:15:29 +00002047 /* Prefix write. */
2048 stream_put_prefix (s, p);
2049
2050 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002051 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002052 }
2053#endif /* HAVE_IPV6 */
2054
2055 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2056 {
2057 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002058
2059 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2060 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002061 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002062 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002063 stream_putw (s, AFI_IP); /* AFI */
2064 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2065
2066 stream_putc (s, 4);
2067 stream_put_ipv4 (s, attr->nexthop.s_addr);
2068
2069 /* SNPA */
2070 stream_putc (s, 0);
2071
paul718e3742002-12-13 20:15:29 +00002072 /* Prefix write. */
2073 stream_put_prefix (s, p);
2074
2075 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002076 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002077 }
2078
2079 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2080 {
2081 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002082
2083 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2084 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002085 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002086 stream_putc (s, 0); /* Length of this attribute. */
2087 stream_putw (s, AFI_IP); /* AFI */
2088 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2089
2090 stream_putc (s, 12);
2091 stream_putl (s, 0);
2092 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002093 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002094
2095 /* SNPA */
2096 stream_putc (s, 0);
2097
paul718e3742002-12-13 20:15:29 +00002098 /* Tag, RD, Prefix write. */
2099 stream_putc (s, p->prefixlen + 88);
2100 stream_put (s, tag, 3);
2101 stream_put (s, prd->val, 8);
2102 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2103
2104 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002105 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002106 }
2107
2108 /* Extended Communities attribute. */
2109 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2110 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2111 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002112 struct attr_extra *attre = attr->extra;
2113
2114 assert (attre);
2115
2116 if (peer_sort (peer) == BGP_PEER_IBGP
2117 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002118 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002119 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002120 {
2121 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2122 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002123 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002124 }
2125 else
2126 {
2127 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2128 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002129 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002130 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002131 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002132 }
2133 else
2134 {
paul5228ad22004-06-04 17:58:18 +00002135 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002136 int tbit;
2137 int ecom_tr_size = 0;
2138 int i;
2139
Paul Jakmafb982c22007-05-04 20:15:47 +00002140 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002141 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002142 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002143 tbit = *pnt;
2144
2145 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2146 continue;
2147
2148 ecom_tr_size++;
2149 }
2150
2151 if (ecom_tr_size)
2152 {
2153 if (ecom_tr_size * 8 > 255)
2154 {
2155 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2156 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2157 stream_putw (s, ecom_tr_size * 8);
2158 }
2159 else
2160 {
2161 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2162 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2163 stream_putc (s, ecom_tr_size * 8);
2164 }
2165
Paul Jakmafb982c22007-05-04 20:15:47 +00002166 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002167 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002168 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002169 tbit = *pnt;
2170
2171 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2172 continue;
2173
2174 stream_put (s, pnt, 8);
2175 }
2176 }
paul718e3742002-12-13 20:15:29 +00002177 }
paul718e3742002-12-13 20:15:29 +00002178 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002179
2180 if ( send_as4_path )
2181 {
2182 /* If the peer is NOT As4 capable, AND */
2183 /* there are ASnums > 65535 in path THEN
2184 * give out AS4_PATH */
2185
2186 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2187 * path segments!
2188 * Hm, I wonder... confederation things *should* only be at
2189 * the beginning of an aspath, right? Then we should use
2190 * aspath_delete_confed_seq for this, because it is already
2191 * there! (JK)
2192 * Folks, talk to me: what is reasonable here!?
2193 */
2194 aspath = aspath_delete_confed_seq (aspath);
2195
2196 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2197 stream_putc (s, BGP_ATTR_AS4_PATH);
2198 aspath_sizep = stream_get_endp (s);
2199 stream_putw (s, 0);
2200 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2201 }
2202
2203 if (aspath != attr->aspath)
2204 aspath_free (aspath);
2205
2206 if ( send_as4_aggregator )
2207 {
2208 assert (attr->extra);
2209
2210 /* send AS4_AGGREGATOR, at this place */
2211 /* this section of code moved here in order to ensure the correct
2212 * *ascending* order of attributes
2213 */
2214 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2215 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2216 stream_putc (s, 8);
2217 stream_putl (s, attr->extra->aggregator_as);
2218 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2219 }
Paul Jakma41367172007-08-06 15:24:51 +00002220
2221 /* AS-Pathlimit */
2222 if (attr->pathlimit.ttl)
2223 {
2224 u_int32_t as = attr->pathlimit.as;
2225
2226 /* should already have been done in announce_check(),
2227 * but just in case..
2228 */
2229 if (!as)
2230 as = peer->local_as;
2231
2232 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2233 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2234 stream_putc (s, 5);
2235 stream_putc (s, attr->pathlimit.ttl);
2236 stream_putl (s, as);
2237 }
2238
paul718e3742002-12-13 20:15:29 +00002239 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002240 if (attr->extra && attr->extra->transit)
2241 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002242
2243 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002244 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002245}
2246
2247bgp_size_t
2248bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2249 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002250 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002251{
2252 unsigned long cp;
2253 unsigned long attrlen_pnt;
2254 bgp_size_t size;
2255
paul9985f832005-02-09 15:51:56 +00002256 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002257
2258 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2259 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2260
paul9985f832005-02-09 15:51:56 +00002261 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002262 stream_putc (s, 0); /* Length of this attribute. */
2263
2264 stream_putw (s, family2afi (p->family));
2265
2266 if (safi == SAFI_MPLS_VPN)
2267 {
2268 /* SAFI */
2269 stream_putc (s, BGP_SAFI_VPNV4);
2270
2271 /* prefix. */
2272 stream_putc (s, p->prefixlen + 88);
2273 stream_put (s, tag, 3);
2274 stream_put (s, prd->val, 8);
2275 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2276 }
2277 else
2278 {
2279 /* SAFI */
2280 stream_putc (s, safi);
2281
2282 /* prefix */
2283 stream_put_prefix (s, p);
2284 }
2285
2286 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002287 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002288 stream_putc_at (s, attrlen_pnt, size);
2289
paul9985f832005-02-09 15:51:56 +00002290 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002291}
2292
2293/* Initialization of attribute. */
2294void
paulfe69a502005-09-10 16:55:02 +00002295bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002296{
paul718e3742002-12-13 20:15:29 +00002297 aspath_init ();
2298 attrhash_init ();
2299 community_init ();
2300 ecommunity_init ();
2301 cluster_init ();
2302 transit_init ();
2303}
2304
2305/* Make attribute packet. */
2306void
paula3845922003-10-18 01:30:50 +00002307bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2308 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002309{
2310 unsigned long cp;
2311 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002312 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002313 struct aspath *aspath;
2314
2315 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002316 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002317
2318 /* Place holder of length. */
2319 stream_putw (s, 0);
2320
2321 /* Origin attribute. */
2322 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2323 stream_putc (s, BGP_ATTR_ORIGIN);
2324 stream_putc (s, 1);
2325 stream_putc (s, attr->origin);
2326
2327 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002328
2329 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2330 stream_putc (s, BGP_ATTR_AS_PATH);
2331 aspath_lenp = stream_get_endp (s);
2332 stream_putw (s, 0);
2333
2334 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002335
2336 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002337 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2338 if(prefix != NULL
2339#ifdef HAVE_IPV6
2340 && prefix->family != AF_INET6
2341#endif /* HAVE_IPV6 */
2342 )
2343 {
2344 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2345 stream_putc (s, BGP_ATTR_NEXT_HOP);
2346 stream_putc (s, 4);
2347 stream_put_ipv4 (s, attr->nexthop.s_addr);
2348 }
paul718e3742002-12-13 20:15:29 +00002349
2350 /* MED attribute. */
2351 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2352 {
2353 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2354 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2355 stream_putc (s, 4);
2356 stream_putl (s, attr->med);
2357 }
2358
2359 /* Local preference. */
2360 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2361 {
2362 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2363 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2364 stream_putc (s, 4);
2365 stream_putl (s, attr->local_pref);
2366 }
2367
2368 /* Atomic aggregate. */
2369 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2370 {
2371 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2372 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2373 stream_putc (s, 0);
2374 }
2375
2376 /* Aggregator. */
2377 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2378 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002379 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002380 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2381 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002382 stream_putc (s, 8);
2383 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002384 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002385 }
2386
2387 /* Community attribute. */
2388 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2389 {
2390 if (attr->community->size * 4 > 255)
2391 {
2392 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2393 stream_putc (s, BGP_ATTR_COMMUNITIES);
2394 stream_putw (s, attr->community->size * 4);
2395 }
2396 else
2397 {
2398 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2399 stream_putc (s, BGP_ATTR_COMMUNITIES);
2400 stream_putc (s, attr->community->size * 4);
2401 }
2402 stream_put (s, attr->community->val, attr->community->size * 4);
2403 }
2404
paula3845922003-10-18 01:30:50 +00002405#ifdef HAVE_IPV6
2406 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002407 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2408 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002409 {
2410 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 struct attr_extra *attre = attr->extra;
2412
paula3845922003-10-18 01:30:50 +00002413 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2414 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002415 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002416
2417 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002418 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002419 stream_putw(s, AFI_IP6); /* AFI */
2420 stream_putc(s, SAFI_UNICAST); /* SAFI */
2421
2422 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002423 stream_putc(s, attre->mp_nexthop_len);
2424 stream_put(s, &attre->mp_nexthop_global, 16);
2425 if (attre->mp_nexthop_len == 32)
2426 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002427
2428 /* SNPA */
2429 stream_putc(s, 0);
2430
2431 /* Prefix */
2432 stream_put_prefix(s, prefix);
2433
2434 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002435 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002436 }
2437#endif /* HAVE_IPV6 */
2438
Paul Jakma41367172007-08-06 15:24:51 +00002439 /* AS-Pathlimit */
2440 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2441 {
2442 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2443 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2444 stream_putc (s, 5);
2445 stream_putc (s, attr->pathlimit.ttl);
2446 stream_putl (s, attr->pathlimit.as);
2447 }
2448
paul718e3742002-12-13 20:15:29 +00002449 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002450 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002451 stream_putw_at (s, cp, len);
2452}