blob: 45a17fac36d23b21e633622b5699e37e107e9d54 [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"
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -070031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_route.h"
36#include "bgpd/bgp_aspath.h"
37#include "bgpd/bgp_community.h"
38#include "bgpd/bgp_debug.h"
39#include "bgpd/bgp_packet.h"
40#include "bgpd/bgp_ecommunity.h"
41
42/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070043static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000044{
45 { BGP_ATTR_ORIGIN, "ORIGIN" },
46 { BGP_ATTR_AS_PATH, "AS_PATH" },
47 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
54 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
55 { BGP_ATTR_DPA, "DPA" },
56 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000064};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070065static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000066
Stephen Hemminger9bddac42009-05-15 09:59:51 -070067static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000068
paul94f2b392005-06-28 12:44:16 +000069static void *
Paul Jakma923de652007-04-29 18:25:17 +000070cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000071{
Paul Jakma923de652007-04-29 18:25:17 +000072 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000073 struct cluster_list *cluster;
74
75 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
76 cluster->length = val->length;
77
78 if (cluster->length)
79 {
80 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
81 memcpy (cluster->list, val->list, val->length);
82 }
83 else
84 cluster->list = NULL;
85
86 cluster->refcnt = 0;
87
88 return cluster;
89}
90
91/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000092static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000093cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000094{
95 struct cluster_list tmp;
96 struct cluster_list *cluster;
97
98 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000099 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000100
101 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
102 cluster->refcnt++;
103 return cluster;
104}
105
106int
107cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
108{
109 int i;
110
111 for (i = 0; i < cluster->length / 4; i++)
112 if (cluster->list[i].s_addr == originator.s_addr)
113 return 1;
114 return 0;
115}
116
paul94f2b392005-06-28 12:44:16 +0000117static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000118cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000119{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700120 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000121
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700122 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000123}
124
paul94f2b392005-06-28 12:44:16 +0000125static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100126cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000127{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100128 const struct cluster_list * cluster1 = p1;
129 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000130
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100131 return (cluster1->length == cluster2->length &&
132 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000133}
134
paul94f2b392005-06-28 12:44:16 +0000135static void
paul718e3742002-12-13 20:15:29 +0000136cluster_free (struct cluster_list *cluster)
137{
138 if (cluster->list)
139 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
140 XFREE (MTYPE_CLUSTER, cluster);
141}
142
Chris Caputo228da422009-07-18 05:44:03 +0000143#if 0
paul94f2b392005-06-28 12:44:16 +0000144static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000145cluster_dup (struct cluster_list *cluster)
146{
147 struct cluster_list *new;
148
Stephen Hemminger393deb92008-08-18 14:13:29 -0700149 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000150 new->length = cluster->length;
151
152 if (cluster->length)
153 {
154 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
155 memcpy (new->list, cluster->list, cluster->length);
156 }
157 else
158 new->list = NULL;
159
160 return new;
161}
Chris Caputo228da422009-07-18 05:44:03 +0000162#endif
paul718e3742002-12-13 20:15:29 +0000163
paul94f2b392005-06-28 12:44:16 +0000164static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000165cluster_intern (struct cluster_list *cluster)
166{
167 struct cluster_list *find;
168
169 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
170 find->refcnt++;
171
172 return find;
173}
174
175void
176cluster_unintern (struct cluster_list *cluster)
177{
178 struct cluster_list *ret;
179
180 if (cluster->refcnt)
181 cluster->refcnt--;
182
183 if (cluster->refcnt == 0)
184 {
185 ret = hash_release (cluster_hash, cluster);
186 cluster_free (cluster);
187 }
188}
189
paul94f2b392005-06-28 12:44:16 +0000190static void
191cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000192{
193 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
194}
Chris Caputo228da422009-07-18 05:44:03 +0000195
196static void
197cluster_finish (void)
198{
199 hash_free (cluster_hash);
200 cluster_hash = NULL;
201}
paul718e3742002-12-13 20:15:29 +0000202
203/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700204static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000205
paul94f2b392005-06-28 12:44:16 +0000206static void
paul718e3742002-12-13 20:15:29 +0000207transit_free (struct transit *transit)
208{
209 if (transit->val)
210 XFREE (MTYPE_TRANSIT_VAL, transit->val);
211 XFREE (MTYPE_TRANSIT, transit);
212}
213
Paul Jakma923de652007-04-29 18:25:17 +0000214
paul94f2b392005-06-28 12:44:16 +0000215static void *
Paul Jakma923de652007-04-29 18:25:17 +0000216transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000217{
218 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000219 return p;
paul718e3742002-12-13 20:15:29 +0000220}
221
paul94f2b392005-06-28 12:44:16 +0000222static struct transit *
paul718e3742002-12-13 20:15:29 +0000223transit_intern (struct transit *transit)
224{
225 struct transit *find;
226
227 find = hash_get (transit_hash, transit, transit_hash_alloc);
228 if (find != transit)
229 transit_free (transit);
230 find->refcnt++;
231
232 return find;
233}
234
235void
236transit_unintern (struct transit *transit)
237{
238 struct transit *ret;
239
240 if (transit->refcnt)
241 transit->refcnt--;
242
243 if (transit->refcnt == 0)
244 {
245 ret = hash_release (transit_hash, transit);
246 transit_free (transit);
247 }
248}
249
paul94f2b392005-06-28 12:44:16 +0000250static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000251transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000252{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700253 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000254
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700255 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000256}
257
paul94f2b392005-06-28 12:44:16 +0000258static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100259transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000260{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100261 const struct transit * transit1 = p1;
262 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000263
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100264 return (transit1->length == transit2->length &&
265 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000266}
267
paul94f2b392005-06-28 12:44:16 +0000268static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800269transit_init (void)
paul718e3742002-12-13 20:15:29 +0000270{
271 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
272}
Chris Caputo228da422009-07-18 05:44:03 +0000273
274static void
275transit_finish (void)
276{
277 hash_free (transit_hash);
278 transit_hash = NULL;
279}
paul718e3742002-12-13 20:15:29 +0000280
281/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700282static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000283
Paul Jakmafb982c22007-05-04 20:15:47 +0000284static struct attr_extra *
285bgp_attr_extra_new (void)
286{
287 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
288}
289
290void
291bgp_attr_extra_free (struct attr *attr)
292{
293 if (attr->extra)
294 {
295 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
296 attr->extra = NULL;
297 }
298}
299
300struct attr_extra *
301bgp_attr_extra_get (struct attr *attr)
302{
303 if (!attr->extra)
304 attr->extra = bgp_attr_extra_new();
305 return attr->extra;
306}
307
308/* Shallow copy of an attribute
309 * Though, not so shallow that it doesn't copy the contents
310 * of the attr_extra pointed to by 'extra'
311 */
312void
313bgp_attr_dup (struct attr *new, struct attr *orig)
314{
315 *new = *orig;
316 if (orig->extra)
317 {
318 new->extra = bgp_attr_extra_new();
319 *new->extra = *orig->extra;
320 }
321}
322
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000323unsigned long int
324attr_count (void)
325{
326 return attrhash->count;
327}
328
329unsigned long int
330attr_unknown_count (void)
331{
332 return transit_hash->count;
333}
334
paul718e3742002-12-13 20:15:29 +0000335unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000336attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000337{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700338 const struct attr * attr = (struct attr *) p;
339 uint32_t key = 0;
340#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000341
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700342 MIX(attr->origin);
343 MIX(attr->nexthop.s_addr);
344 MIX(attr->med);
345 MIX(attr->local_pref);
346
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000347 key += attr->origin;
348 key += attr->nexthop.s_addr;
349 key += attr->med;
350 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000351
352 if (attr->extra)
353 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700354 MIX(attr->extra->aggregator_as);
355 MIX(attr->extra->aggregator_addr.s_addr);
356 MIX(attr->extra->weight);
357 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000358 }
359
paul718e3742002-12-13 20:15:29 +0000360 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700361 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000362 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700363 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000364
365 if (attr->extra)
366 {
367 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700368 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000369 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700370 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000371 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700372 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000373
374#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700375 MIX(attr->extra->mp_nexthop_len);
Paul Jakma31d0f1b2011-03-29 14:18:49 +0100376 key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
377 key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000378#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000379 }
paul718e3742002-12-13 20:15:29 +0000380
381 return key;
382}
383
384int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100385attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000386{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100387 const struct attr * attr1 = p1;
388 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000389
paul718e3742002-12-13 20:15:29 +0000390 if (attr1->flag == attr2->flag
391 && attr1->origin == attr2->origin
392 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000393 && attr1->aspath == attr2->aspath
394 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000395 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000396 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000397 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100398 const struct attr_extra *ae1 = attr1->extra;
399 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000400
401 if (ae1 && ae2
402 && ae1->aggregator_as == ae2->aggregator_as
403 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
404 && ae1->weight == ae2->weight
405#ifdef HAVE_IPV6
406 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
407 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
408 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
409#endif /* HAVE_IPV6 */
410 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
411 && ae1->ecommunity == ae2->ecommunity
412 && ae1->cluster == ae2->cluster
413 && ae1->transit == ae2->transit)
414 return 1;
415 else if (ae1 || ae2)
416 return 0;
417 /* neither attribute has extra attributes, so they're same */
418 return 1;
419 }
paul718e3742002-12-13 20:15:29 +0000420 else
421 return 0;
422}
423
paul94f2b392005-06-28 12:44:16 +0000424static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100425attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000426{
427 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
428}
429
paul94f2b392005-06-28 12:44:16 +0000430static void
Chris Caputo228da422009-07-18 05:44:03 +0000431attrhash_finish (void)
432{
433 hash_free (attrhash);
434 attrhash = NULL;
435}
436
437static void
paul718e3742002-12-13 20:15:29 +0000438attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
439{
440 struct attr *attr = backet->data;
441
442 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
443 inet_ntoa (attr->nexthop), VTY_NEWLINE);
444}
445
446void
447attr_show_all (struct vty *vty)
448{
449 hash_iterate (attrhash,
450 (void (*)(struct hash_backet *, void *))
451 attr_show_all_iterator,
452 vty);
453}
454
paul94f2b392005-06-28 12:44:16 +0000455static void *
Paul Jakma923de652007-04-29 18:25:17 +0000456bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000457{
Paul Jakma923de652007-04-29 18:25:17 +0000458 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000459 struct attr *attr;
460
461 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
462 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000463 if (val->extra)
464 {
465 attr->extra = bgp_attr_extra_new ();
466 *attr->extra = *val->extra;
467 }
paul718e3742002-12-13 20:15:29 +0000468 attr->refcnt = 0;
469 return attr;
470}
471
472/* Internet argument attribute. */
473struct attr *
474bgp_attr_intern (struct attr *attr)
475{
476 struct attr *find;
477
478 /* Intern referenced strucutre. */
479 if (attr->aspath)
480 {
481 if (! attr->aspath->refcnt)
482 attr->aspath = aspath_intern (attr->aspath);
483 else
484 attr->aspath->refcnt++;
485 }
486 if (attr->community)
487 {
488 if (! attr->community->refcnt)
489 attr->community = community_intern (attr->community);
490 else
491 attr->community->refcnt++;
492 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000493 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000494 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000495 struct attr_extra *attre = attr->extra;
496
497 if (attre->ecommunity)
498 {
499 if (! attre->ecommunity->refcnt)
500 attre->ecommunity = ecommunity_intern (attre->ecommunity);
501 else
502 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000503
Paul Jakmafb982c22007-05-04 20:15:47 +0000504 }
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 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000520
paul718e3742002-12-13 20:15:29 +0000521 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
522 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000523
paul718e3742002-12-13 20:15:29 +0000524 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
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000565 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000566 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
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000617 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000618 return new;
619}
620
Paul Jakmab881c702010-11-23 16:35:42 +0000621/* Unintern just the sub-components of the attr, but not the attr */
622void
623bgp_attr_unintern_sub (struct attr *attr)
624{
625 /* aspath refcount shoud be decrement. */
626 if (attr->aspath)
627 aspath_unintern (&attr->aspath);
628 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
629
630 if (attr->community)
631 community_unintern (&attr->community);
632 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
633
634 if (attr->extra)
635 {
636 if (attr->extra->ecommunity)
637 ecommunity_unintern (&attr->extra->ecommunity);
638 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
639
640 if (attr->extra->cluster)
641 cluster_unintern (attr->extra->cluster);
642 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
643
644 if (attr->extra->transit)
645 transit_unintern (attr->extra->transit);
646 }
647}
648
paul718e3742002-12-13 20:15:29 +0000649/* Free bgp attribute and aspath. */
650void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000651bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000652{
653 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000654 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000655
paul718e3742002-12-13 20:15:29 +0000656 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000657 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000658
659 tmp = *(*attr);
660
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000662 {
Paul Jakmab881c702010-11-23 16:35:42 +0000663 tmp.extra = bgp_attr_extra_new ();
664 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000665 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000666
paul718e3742002-12-13 20:15:29 +0000667 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000668 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000669 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000670 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000671 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672 bgp_attr_extra_free (*attr);
673 XFREE (MTYPE_ATTR, *attr);
674 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000675 }
676
Paul Jakmab881c702010-11-23 16:35:42 +0000677 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000678}
679
680void
681bgp_attr_flush (struct attr *attr)
682{
683 if (attr->aspath && ! attr->aspath->refcnt)
684 aspath_free (attr->aspath);
685 if (attr->community && ! attr->community->refcnt)
686 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000687 if (attr->extra)
688 {
689 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000690
Paul Jakmafb982c22007-05-04 20:15:47 +0000691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000692 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000693 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
Paul Jakmab881c702010-11-23 16:35:42 +0000700/* Implement draft-scudder-idr-optional-transitive behaviour and
701 * avoid resetting sessions for malformed attributes which are
702 * are partial/optional and hence where the error likely was not
703 * introduced by the sending neighbour.
704 */
705static bgp_attr_parse_ret_t
706bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
707 u_char subcode, u_char *startp, bgp_size_t length)
708{
709 /* Only relax error handling for eBGP peers */
710 if (peer_sort (peer) != BGP_PEER_EBGP)
711 {
712 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
713 startp, length);
714 return BGP_ATTR_PARSE_ERROR;
715
716 }
717
718 switch (type) {
719 /* where an optional attribute is inconsequential, e.g. it does not affect
720 * route selection, and can be safely ignored then any such attributes
721 * which are malformed should just be ignored and the route processed as
722 * normal.
723 */
724 case BGP_ATTR_AS4_AGGREGATOR:
725 case BGP_ATTR_AGGREGATOR:
726 case BGP_ATTR_ATOMIC_AGGREGATE:
727 return BGP_ATTR_PARSE_PROCEED;
728
729 /* Core attributes, particularly ones which may influence route
730 * selection should always cause session resets
731 */
732 case BGP_ATTR_ORIGIN:
733 case BGP_ATTR_AS_PATH:
734 case BGP_ATTR_NEXT_HOP:
735 case BGP_ATTR_MULTI_EXIT_DISC:
736 case BGP_ATTR_LOCAL_PREF:
737 case BGP_ATTR_COMMUNITIES:
738 case BGP_ATTR_ORIGINATOR_ID:
739 case BGP_ATTR_CLUSTER_LIST:
740 case BGP_ATTR_MP_REACH_NLRI:
741 case BGP_ATTR_MP_UNREACH_NLRI:
742 case BGP_ATTR_EXT_COMMUNITIES:
743 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
744 startp, length);
745 return BGP_ATTR_PARSE_ERROR;
746 }
747
748 /* Partial optional attributes that are malformed should not cause
749 * the whole session to be reset. Instead treat it as a withdrawal
750 * of the routes, if possible.
751 */
752 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
753 && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
754 && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
755 return BGP_ATTR_PARSE_WITHDRAW;
756
757 /* default to reset */
758 return BGP_ATTR_PARSE_ERROR;
759}
760
paul718e3742002-12-13 20:15:29 +0000761/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000762static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000763bgp_attr_origin (struct peer *peer, bgp_size_t length,
764 struct attr *attr, u_char flag, u_char *startp)
765{
766 bgp_size_t total;
767
768 /* total is entire attribute length include Attribute Flags (1),
769 Attribute Type code (1) and Attribute length (1 or 2). */
770 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
771
772 /* If any recognized attribute has Attribute Flags that conflict
773 with the Attribute Type Code, then the Error Subcode is set to
774 Attribute Flags Error. The Data field contains the erroneous
775 attribute (type, length and value). */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400776 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +0000777 {
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400778 zlog (peer->log, LOG_ERR,
779 "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000780 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
781 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
782 startp, total);
paul718e3742002-12-13 20:15:29 +0000783 }
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400784 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
785 {
786 zlog (peer->log, LOG_ERR,
787 "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
788 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
789 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
790 startp, total);
791 }
792 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
793 {
794 zlog (peer->log, LOG_ERR,
795 "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
796 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
797 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
798 startp, total);
799 }
paul718e3742002-12-13 20:15:29 +0000800
801 /* If any recognized attribute has Attribute Length that conflicts
802 with the expected length (based on the attribute type code), then
803 the Error Subcode is set to Attribute Length Error. The Data
804 field contains the erroneous attribute (type, length and
805 value). */
806 if (length != 1)
807 {
808 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
809 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000810 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
811 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
812 startp, total);
paul718e3742002-12-13 20:15:29 +0000813 }
814
815 /* Fetch origin attribute. */
816 attr->origin = stream_getc (BGP_INPUT (peer));
817
818 /* If the ORIGIN attribute has an undefined value, then the Error
819 Subcode is set to Invalid Origin Attribute. The Data field
820 contains the unrecognized attribute (type, length and value). */
821 if ((attr->origin != BGP_ORIGIN_IGP)
822 && (attr->origin != BGP_ORIGIN_EGP)
823 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
824 {
825 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
826 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000827 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
828 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
829 startp, total);
paul718e3742002-12-13 20:15:29 +0000830 }
831
832 /* Set oring attribute flag. */
833 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
834
835 return 0;
836}
Paul Jakmaab005292010-11-27 22:48:34 +0000837
838/* Parse AS path information. This function is wrapper of
839 aspath_parse. */
840static int
paul718e3742002-12-13 20:15:29 +0000841bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000842 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000843{
Paul Jakmaab005292010-11-27 22:48:34 +0000844 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000845
Paul Jakmaab005292010-11-27 22:48:34 +0000846 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000847
Paul Jakmaab005292010-11-27 22:48:34 +0000848 /* Flag check. */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400849 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
850 {
851 zlog (peer->log, LOG_ERR,
852 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
853 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
854 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
855 startp, total);
856 }
857
Paul Jakmaab005292010-11-27 22:48:34 +0000858 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
859 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000860 {
861 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000862 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000863 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
864 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
865 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400866 }
Paul Jakmaab005292010-11-27 22:48:34 +0000867
868 /*
869 * peer with AS4 => will get 4Byte ASnums
870 * otherwise, will get 16 Bit
871 */
872 attr->aspath = aspath_parse (peer->ibuf, length,
873 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
874
875 /* In case of IBGP, length will be zero. */
876 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000877 {
Paul Jakmab881c702010-11-23 16:35:42 +0000878 zlog (peer->log, LOG_ERR,
879 "Malformed AS path from %s, length is %d",
880 peer->host, length);
881 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
882 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
883 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000884 }
Chris Hallcddb8112010-08-09 22:31:37 +0400885
Paul Jakmaab005292010-11-27 22:48:34 +0000886 /* Set aspath attribute flag. */
887 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000888
Paul Jakmab881c702010-11-23 16:35:42 +0000889 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000890}
891
Paul Jakmab881c702010-11-23 16:35:42 +0000892static bgp_attr_parse_ret_t
893bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000894{
895 /* These checks were part of bgp_attr_aspath, but with
896 * as4 we should to check aspath things when
897 * aspath synthesizing with as4_path has already taken place.
898 * Otherwise we check ASPATH and use the synthesized thing, and that is
899 * not right.
900 * So do the checks later, i.e. here
901 */
902 struct bgp *bgp = peer->bgp;
903 struct aspath *aspath;
904
paul718e3742002-12-13 20:15:29 +0000905 bgp = peer->bgp;
906
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300907 /* Confederation sanity check. */
908 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
909 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
910 {
911 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000912 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
913 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
914 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300915 }
916
paul718e3742002-12-13 20:15:29 +0000917 /* First AS check for EBGP. */
918 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
919 {
920 if (peer_sort (peer) == BGP_PEER_EBGP
921 && ! aspath_firstas_check (attr->aspath, peer->as))
922 {
923 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400924 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000925 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
926 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
927 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000928 }
929 }
930
931 /* local-as prepend */
932 if (peer->change_local_as &&
933 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
934 {
935 aspath = aspath_dup (attr->aspath);
936 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000937 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000938 attr->aspath = aspath_intern (aspath);
939 }
940
Paul Jakmab881c702010-11-23 16:35:42 +0000941 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000942}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000943
Paul Jakmaab005292010-11-27 22:48:34 +0000944/* Parse AS4 path information. This function is another wrapper of
945 aspath_parse. */
946static int
Paul Jakmab881c702010-11-23 16:35:42 +0000947bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
948 struct attr *attr, u_char flag, u_char *startp,
949 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000950{
Paul Jakmab881c702010-11-23 16:35:42 +0000951 bgp_size_t total;
952
953 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
954
955 /* Flag check. */
956 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
957 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
958 {
959 zlog (peer->log, LOG_ERR,
960 "As4-Path attribute flag isn't optional/transitive %d", flag);
961 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
962 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
963 startp, total);
964 }
965
Paul Jakmaab005292010-11-27 22:48:34 +0000966 *as4_path = aspath_parse (peer->ibuf, length, 1);
967
Paul Jakmab881c702010-11-23 16:35:42 +0000968 /* In case of IBGP, length will be zero. */
969 if (!*as4_path)
970 {
971 zlog (peer->log, LOG_ERR,
972 "Malformed AS4 path from %s, length is %d",
973 peer->host, length);
974 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
975 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
976 NULL, 0);
977 }
978
Paul Jakmaab005292010-11-27 22:48:34 +0000979 /* Set aspath attribute flag. */
980 if (as4_path)
981 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
982
Paul Jakmab881c702010-11-23 16:35:42 +0000983 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000984}
985
paul718e3742002-12-13 20:15:29 +0000986/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000987static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000988bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
989 struct attr *attr, u_char flag, u_char *startp)
990{
991 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400992 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000993
994 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
995
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400996 /* Flags check. */
997 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +0000998 {
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400999 zlog (peer->log, LOG_ERR,
1000 "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
1001 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1002 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1003 startp, total);
1004 }
1005 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1006 {
1007 zlog (peer->log, LOG_ERR,
1008 "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
1009 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1010 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1011 startp, total);
1012 }
1013 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1014 {
1015 zlog (peer->log, LOG_ERR,
1016 "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
Paul Jakmab881c702010-11-23 16:35:42 +00001017 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1018 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1019 startp, total);
paul718e3742002-12-13 20:15:29 +00001020 }
1021
1022 /* Check nexthop attribute length. */
1023 if (length != 4)
1024 {
1025 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1026 length);
1027
Paul Jakmab881c702010-11-23 16:35:42 +00001028 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1029 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1030 startp, total);
paul718e3742002-12-13 20:15:29 +00001031 }
1032
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001033 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1034 attribute must result in a NOTIFICATION message (this is implemented below).
1035 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1036 logged locally (this is implemented somewhere else). The UPDATE message
1037 gets ignored in any of these cases. */
1038 nexthop_n = stream_get_ipv4 (peer->ibuf);
1039 nexthop_h = ntohl (nexthop_n);
1040 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1041 {
1042 char buf[INET_ADDRSTRLEN];
1043 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1044 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1045 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1046 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1047 startp, total);
1048 }
1049
1050 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001051 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1052
Paul Jakmab881c702010-11-23 16:35:42 +00001053 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001054}
1055
1056/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001057static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001058bgp_attr_med (struct peer *peer, bgp_size_t length,
1059 struct attr *attr, u_char flag, u_char *startp)
1060{
1061 bgp_size_t total;
1062
1063 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1064
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001065 /* Flag checks. */
1066 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1067 {
1068 zlog (peer->log, LOG_ERR,
1069 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1070 bgp_notify_send_with_data (peer,
1071 BGP_NOTIFY_UPDATE_ERR,
1072 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1073 startp, total);
1074 return -1;
1075 }
1076 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1077 {
1078 zlog (peer->log, LOG_ERR,
1079 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1080 bgp_notify_send_with_data (peer,
1081 BGP_NOTIFY_UPDATE_ERR,
1082 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1083 startp, total);
1084 return -1;
1085 }
1086 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1087 {
1088 zlog (peer->log, LOG_ERR,
1089 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
1090 bgp_notify_send_with_data (peer,
1091 BGP_NOTIFY_UPDATE_ERR,
1092 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1093 startp, total);
1094 return -1;
1095 }
1096
paul718e3742002-12-13 20:15:29 +00001097 /* Length check. */
1098 if (length != 4)
1099 {
1100 zlog (peer->log, LOG_ERR,
1101 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001102
1103 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1104 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1105 startp, total);
paul718e3742002-12-13 20:15:29 +00001106 }
1107
1108 attr->med = stream_getl (peer->ibuf);
1109
1110 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1111
Paul Jakmab881c702010-11-23 16:35:42 +00001112 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001113}
1114
1115/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001116static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001117bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001118 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001119{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001120 bgp_size_t total;
1121
1122 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1123 /* Flag checks. */
1124 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1125 {
1126 zlog (peer->log, LOG_ERR,
1127 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1128 bgp_notify_send_with_data (peer,
1129 BGP_NOTIFY_UPDATE_ERR,
1130 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1131 startp, total);
1132 return -1;
1133 }
1134 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1135 {
1136 zlog (peer->log, LOG_ERR,
1137 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1138 bgp_notify_send_with_data (peer,
1139 BGP_NOTIFY_UPDATE_ERR,
1140 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1141 startp, total);
1142 return -1;
1143 }
Denis Ovsienko214bcaa2011-09-24 13:20:43 +04001144 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1145 {
1146 zlog (peer->log, LOG_ERR,
1147 "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1148 bgp_notify_send_with_data (peer,
1149 BGP_NOTIFY_UPDATE_ERR,
1150 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1151 startp, total);
1152 return -1;
1153 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001154
paul718e3742002-12-13 20:15:29 +00001155 /* If it is contained in an UPDATE message that is received from an
1156 external peer, then this attribute MUST be ignored by the
1157 receiving speaker. */
1158 if (peer_sort (peer) == BGP_PEER_EBGP)
1159 {
paul9985f832005-02-09 15:51:56 +00001160 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001161 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001162 }
1163
1164 if (length == 4)
1165 attr->local_pref = stream_getl (peer->ibuf);
1166 else
1167 attr->local_pref = 0;
1168
1169 /* Set atomic aggregate flag. */
1170 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1171
Paul Jakmab881c702010-11-23 16:35:42 +00001172 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001173}
1174
1175/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001176static int
paul718e3742002-12-13 20:15:29 +00001177bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001178 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001179{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001180 bgp_size_t total;
1181
1182 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1183 /* Flag checks. */
1184 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1185 {
1186 zlog (peer->log, LOG_ERR,
1187 "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1188 bgp_notify_send_with_data (peer,
1189 BGP_NOTIFY_UPDATE_ERR,
1190 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1191 startp, total);
1192 return -1;
1193 }
1194 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1195 {
1196 zlog (peer->log, LOG_ERR,
1197 "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1198 bgp_notify_send_with_data (peer,
1199 BGP_NOTIFY_UPDATE_ERR,
1200 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1201 startp, total);
1202 return -1;
1203 }
1204 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1205 {
1206 zlog (peer->log, LOG_ERR,
1207 "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1208 bgp_notify_send_with_data (peer,
1209 BGP_NOTIFY_UPDATE_ERR,
1210 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1211 startp, total);
1212 return -1;
1213 }
1214
1215 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001216 if (length != 0)
1217 {
1218 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1219
Paul Jakmab881c702010-11-23 16:35:42 +00001220 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1221 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1222 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001223 }
1224
1225 /* Set atomic aggregate flag. */
1226 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1227
Paul Jakmab881c702010-11-23 16:35:42 +00001228 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001229}
1230
1231/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001232static int
paul718e3742002-12-13 20:15:29 +00001233bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1234 struct attr *attr, u_char flag)
1235{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001236 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001237 struct attr_extra *attre = bgp_attr_extra_get (attr);
1238
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001239 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001240 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001241 wantedlen = 8;
1242
1243 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001244 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001245 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001246
Paul Jakmab881c702010-11-23 16:35:42 +00001247 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1248 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1249 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001250 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001251
1252 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1253 attre->aggregator_as = stream_getl (peer->ibuf);
1254 else
1255 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001256 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001257
1258 /* Set atomic aggregate flag. */
1259 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1260
Paul Jakmab881c702010-11-23 16:35:42 +00001261 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001262}
1263
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001264/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001265static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001266bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001267 struct attr *attr, u_char flag,
1268 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001269 struct in_addr *as4_aggregator_addr)
1270{
1271 if (length != 8)
1272 {
1273 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001274 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1275 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1276 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001277 }
1278 *as4_aggregator_as = stream_getl (peer->ibuf);
1279 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1280
1281 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1282
Paul Jakmab881c702010-11-23 16:35:42 +00001283 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001284}
1285
1286/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1287 */
Paul Jakmab881c702010-11-23 16:35:42 +00001288static bgp_attr_parse_ret_t
1289bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001290 struct aspath *as4_path, as_t as4_aggregator,
1291 struct in_addr *as4_aggregator_addr)
1292{
1293 int ignore_as4_path = 0;
1294 struct aspath *newpath;
1295 struct attr_extra *attre = attr->extra;
1296
Paul Jakmab881c702010-11-23 16:35:42 +00001297 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001298 {
1299 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1300 * if given.
1301 * It is worth a warning though, because the peer really
1302 * should not send them
1303 */
1304 if (BGP_DEBUG(as4, AS4))
1305 {
1306 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1307 zlog_debug ("[AS4] %s %s AS4_PATH",
1308 peer->host, "AS4 capable peer, yet it sent");
1309
1310 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1311 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1312 peer->host, "AS4 capable peer, yet it sent");
1313 }
1314
Paul Jakmab881c702010-11-23 16:35:42 +00001315 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001316 }
1317
Paul Jakmab881c702010-11-23 16:35:42 +00001318 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1319 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001320 {
1321 /* Hu? This is not supposed to happen at all!
1322 * got as4_path and no aspath,
1323 * This should already
1324 * have been handled by 'well known attributes missing'
1325 * But... yeah, paranoia
1326 * Take this as a "malformed attribute"
1327 */
1328 zlog (peer->log, LOG_ERR,
1329 "%s BGP not AS4 capable peer sent AS4_PATH but"
1330 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001331 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1332 BGP_NOTIFY_UPDATE_MAL_ATTR,
1333 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001334 }
1335
1336 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1337 * because that may override AS4_PATH
1338 */
1339 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1340 {
Paul Jakmab881c702010-11-23 16:35:42 +00001341 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001342 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001343 assert (attre);
1344
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001345 /* received both.
1346 * if the as_number in aggregator is not AS_TRANS,
1347 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1348 * and the Aggregator shall be taken as
1349 * info on the aggregating node, and the AS_PATH
1350 * shall be taken as the AS_PATH
1351 * otherwise
1352 * the Aggregator shall be ignored and the
1353 * AS4_AGGREGATOR shall be taken as the
1354 * Aggregating node and the AS_PATH is to be
1355 * constructed "as in all other cases"
1356 */
Paul Jakmab881c702010-11-23 16:35:42 +00001357 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001358 {
1359 /* ignore */
1360 if ( BGP_DEBUG(as4, AS4))
1361 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1362 " send AGGREGATOR != AS_TRANS and"
1363 " AS4_AGGREGATOR, so ignore"
1364 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1365 ignore_as4_path = 1;
1366 }
1367 else
1368 {
1369 /* "New_aggregator shall be taken as aggregator" */
1370 attre->aggregator_as = as4_aggregator;
1371 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1372 }
1373 }
1374 else
1375 {
1376 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1377 * That is bogus - but reading the conditions
1378 * we have to handle AS4_AGGREGATOR as if it were
1379 * AGGREGATOR in that case
1380 */
1381 if ( BGP_DEBUG(as4, AS4))
1382 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1383 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1384 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001385 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001386 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1387 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1388 }
1389 }
1390
1391 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001392 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001393 {
1394 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001395 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001396 attr->aspath = aspath_intern (newpath);
1397 }
Paul Jakmab881c702010-11-23 16:35:42 +00001398 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001399}
1400
paul718e3742002-12-13 20:15:29 +00001401/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001402static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001403bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001404 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001405{
Paul Jakmab881c702010-11-23 16:35:42 +00001406 bgp_size_t total
1407 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1408
paul718e3742002-12-13 20:15:29 +00001409 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001410 {
1411 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001412 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001413 }
Paul Jakma0c466382010-12-05 17:17:26 +00001414
1415 attr->community =
1416 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1417
1418 /* XXX: fix community_parse to use stream API and remove this */
1419 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001420
Paul Jakma0c466382010-12-05 17:17:26 +00001421 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001422 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1423 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1424 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001425
paul718e3742002-12-13 20:15:29 +00001426 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1427
Paul Jakmab881c702010-11-23 16:35:42 +00001428 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001429}
1430
1431/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001432static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001433bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1434 struct attr *attr, u_char flag)
1435{
1436 if (length != 4)
1437 {
1438 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1439
Paul Jakmab881c702010-11-23 16:35:42 +00001440 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1441 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1442 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001443 }
1444
Paul Jakmafb982c22007-05-04 20:15:47 +00001445 (bgp_attr_extra_get (attr))->originator_id.s_addr
1446 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001447
1448 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1449
Paul Jakmab881c702010-11-23 16:35:42 +00001450 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001451}
1452
1453/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001454static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001455bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1456 struct attr *attr, u_char flag)
1457{
1458 /* Check length. */
1459 if (length % 4)
1460 {
1461 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1462
Paul Jakmab881c702010-11-23 16:35:42 +00001463 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1464 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1465 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001466 }
1467
Paul Jakmafb982c22007-05-04 20:15:47 +00001468 (bgp_attr_extra_get (attr))->cluster
1469 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001470
1471 /* XXX: Fix cluster_parse to use stream API and then remove this */
1472 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001473
1474 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1475
Paul Jakmab881c702010-11-23 16:35:42 +00001476 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001477}
1478
1479/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001480int
paul718e3742002-12-13 20:15:29 +00001481bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1482 struct bgp_nlri *mp_update)
1483{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001484 afi_t afi;
1485 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001486 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001487 size_t start;
paul718e3742002-12-13 20:15:29 +00001488 int ret;
1489 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001490 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001491
1492 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001493 s = BGP_INPUT(peer);
1494 start = stream_get_getp(s);
1495
1496 /* safe to read statically sized header? */
1497#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001498#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001499 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001500 {
1501 zlog_info ("%s: %s sent invalid length, %lu",
1502 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001503 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001504 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001505
paul718e3742002-12-13 20:15:29 +00001506 /* Load AFI, SAFI. */
1507 afi = stream_getw (s);
1508 safi = stream_getc (s);
1509
1510 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001511 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001512
Paul Jakma03292802008-06-07 20:37:10 +00001513 if (LEN_LEFT < attre->mp_nexthop_len)
1514 {
1515 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1516 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001517 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001518 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001519
paul718e3742002-12-13 20:15:29 +00001520 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001521 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001522 {
1523 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001524 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001525 /* Probably needed for RFC 2283 */
1526 if (attr->nexthop.s_addr == 0)
1527 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001528 break;
1529 case 12:
1530 {
1531 u_int32_t rd_high;
1532 u_int32_t rd_low;
1533
1534 rd_high = stream_getl (s);
1535 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001536 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001537 }
1538 break;
1539#ifdef HAVE_IPV6
1540 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001541 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001542 break;
1543 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001544 stream_get (&attre->mp_nexthop_global, s, 16);
1545 stream_get (&attre->mp_nexthop_local, s, 16);
1546 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001547 {
1548 char buf1[INET6_ADDRSTRLEN];
1549 char buf2[INET6_ADDRSTRLEN];
1550
1551 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001552 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 +00001553 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001554 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001555 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001556 buf2, INET6_ADDRSTRLEN));
1557
Paul Jakmafb982c22007-05-04 20:15:47 +00001558 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001559 }
1560 break;
1561#endif /* HAVE_IPV6 */
1562 default:
Paul Jakma03292802008-06-07 20:37:10 +00001563 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1564 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001565 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001566 }
1567
Paul Jakma03292802008-06-07 20:37:10 +00001568 if (!LEN_LEFT)
1569 {
1570 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1571 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001572 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001573 }
paul718e3742002-12-13 20:15:29 +00001574
Paul Jakma6e4ab122007-04-10 19:36:48 +00001575 {
1576 u_char val;
1577 if ((val = stream_getc (s)))
1578 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1579 peer->host, val);
1580 }
1581
1582 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001583 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001584 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001585 {
1586 zlog_info ("%s: (%s) Failed to read NLRI",
1587 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001588 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001589 }
paul718e3742002-12-13 20:15:29 +00001590
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001591 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001592 {
1593 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001594 if (ret < 0)
1595 {
1596 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1597 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001598 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001599 }
paul718e3742002-12-13 20:15:29 +00001600 }
1601
1602 mp_update->afi = afi;
1603 mp_update->safi = safi;
1604 mp_update->nlri = stream_pnt (s);
1605 mp_update->length = nlri_len;
1606
paul9985f832005-02-09 15:51:56 +00001607 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001608
Paul Jakmab881c702010-11-23 16:35:42 +00001609 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001610#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001611}
1612
1613/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001614int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001615bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001616 struct bgp_nlri *mp_withdraw)
1617{
1618 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001619 afi_t afi;
1620 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001621 u_int16_t withdraw_len;
1622 int ret;
1623
1624 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001625
1626#define BGP_MP_UNREACH_MIN_SIZE 3
1627 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001628 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001629
paul718e3742002-12-13 20:15:29 +00001630 afi = stream_getw (s);
1631 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001632
1633 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001634
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001635 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001636 {
1637 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1638 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001639 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001640 }
1641
1642 mp_withdraw->afi = afi;
1643 mp_withdraw->safi = safi;
1644 mp_withdraw->nlri = stream_pnt (s);
1645 mp_withdraw->length = withdraw_len;
1646
paul9985f832005-02-09 15:51:56 +00001647 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001648
Paul Jakmab881c702010-11-23 16:35:42 +00001649 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001650}
1651
1652/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001653static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001654bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001655 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001656{
Paul Jakmab881c702010-11-23 16:35:42 +00001657 bgp_size_t total
1658 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1659
paul718e3742002-12-13 20:15:29 +00001660 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001661 {
1662 if (attr->extra)
1663 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001664 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001665 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001666 }
Paul Jakma0c466382010-12-05 17:17:26 +00001667
1668 (bgp_attr_extra_get (attr))->ecommunity =
1669 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1670 /* XXX: fix ecommunity_parse to use stream API */
1671 stream_forward_getp (peer->ibuf, length);
1672
1673 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001674 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1675 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1676 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001677
paul718e3742002-12-13 20:15:29 +00001678 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1679
Paul Jakmab881c702010-11-23 16:35:42 +00001680 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001681}
1682
1683/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001684static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001685bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1686 u_char type, bgp_size_t length, u_char *startp)
1687{
1688 bgp_size_t total;
1689 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001690 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001691
hassof4184462005-02-01 20:13:16 +00001692 if (BGP_DEBUG (normal, NORMAL))
1693 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1694 peer->host, type, length);
1695
paul718e3742002-12-13 20:15:29 +00001696 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001697 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001698 "Unknown attribute type %d length %d is received", type, length);
1699
1700 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001701 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001702
1703 /* Adjest total length to include type and length. */
1704 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1705
1706 /* If any of the mandatory well-known attributes are not recognized,
1707 then the Error Subcode is set to Unrecognized Well-known
1708 Attribute. The Data field contains the unrecognized attribute
1709 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001710 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001711 {
Paul Jakmab881c702010-11-23 16:35:42 +00001712 return bgp_attr_malformed (peer, type, flag,
1713 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1714 startp, total);
paul718e3742002-12-13 20:15:29 +00001715 }
1716
1717 /* Unrecognized non-transitive optional attributes must be quietly
1718 ignored and not passed along to other BGP peers. */
1719 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001720 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001721
1722 /* If a path with recognized transitive optional attribute is
1723 accepted and passed along to other BGP peers and the Partial bit
1724 in the Attribute Flags octet is set to 1 by some previous AS, it
1725 is not set back to 0 by the current AS. */
1726 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1727
1728 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001729 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001730 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001731
Paul Jakmafb982c22007-05-04 20:15:47 +00001732 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001733
1734 if (transit->val)
1735 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1736 transit->length + total);
1737 else
1738 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1739
1740 memcpy (transit->val + transit->length, startp, total);
1741 transit->length += total;
1742
Paul Jakmab881c702010-11-23 16:35:42 +00001743 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001744}
1745
1746/* Read attribute of update packet. This function is called from
1747 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001748bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001749bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1750 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1751{
1752 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001753 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001754 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001755 bgp_size_t length;
1756 u_char *startp, *endp;
1757 u_char *attr_endp;
1758 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001759 /* we need the as4_path only until we have synthesized the as_path with it */
1760 /* same goes for as4_aggregator */
1761 struct aspath *as4_path = NULL;
1762 as_t as4_aggregator = 0;
1763 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001764
1765 /* Initialize bitmap. */
1766 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1767
1768 /* End pointer of BGP attribute. */
1769 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001770
paul718e3742002-12-13 20:15:29 +00001771 /* Get attributes to the end of attribute length. */
1772 while (BGP_INPUT_PNT (peer) < endp)
1773 {
1774 /* Check remaining length check.*/
1775 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1776 {
gdtc29fdba2004-12-09 14:46:46 +00001777 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001778 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001779 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001780 peer->host,
1781 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001782
1783 bgp_notify_send (peer,
1784 BGP_NOTIFY_UPDATE_ERR,
1785 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001786 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001787 }
1788
1789 /* Fetch attribute flag and type. */
1790 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001791 /* "The lower-order four bits of the Attribute Flags octet are
1792 unused. They MUST be zero when sent and MUST be ignored when
1793 received." */
1794 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001795 type = stream_getc (BGP_INPUT (peer));
1796
Paul Jakma370b64a2007-12-22 16:49:52 +00001797 /* Check whether Extended-Length applies and is in bounds */
1798 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1799 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1800 {
1801 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001802 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001803 peer->host,
1804 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1805
1806 bgp_notify_send (peer,
1807 BGP_NOTIFY_UPDATE_ERR,
1808 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001809 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001810 }
1811
paul718e3742002-12-13 20:15:29 +00001812 /* Check extended attribue length bit. */
1813 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1814 length = stream_getw (BGP_INPUT (peer));
1815 else
1816 length = stream_getc (BGP_INPUT (peer));
1817
1818 /* If any attribute appears more than once in the UPDATE
1819 message, then the Error Subcode is set to Malformed Attribute
1820 List. */
1821
1822 if (CHECK_BITMAP (seen, type))
1823 {
1824 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001825 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001826 peer->host, type);
1827
1828 bgp_notify_send (peer,
1829 BGP_NOTIFY_UPDATE_ERR,
1830 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001831 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001832 }
1833
1834 /* Set type to bitmap to check duplicate attribute. `type' is
1835 unsigned char so it never overflow bitmap range. */
1836
1837 SET_BITMAP (seen, type);
1838
1839 /* Overflow check. */
1840 attr_endp = BGP_INPUT_PNT (peer) + length;
1841
1842 if (attr_endp > endp)
1843 {
1844 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001845 "%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 +00001846 bgp_notify_send (peer,
1847 BGP_NOTIFY_UPDATE_ERR,
1848 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001849 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001850 }
1851
1852 /* OK check attribute and store it's value. */
1853 switch (type)
1854 {
1855 case BGP_ATTR_ORIGIN:
1856 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1857 break;
1858 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001859 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001860 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001861 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001862 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001863 break;
paul718e3742002-12-13 20:15:29 +00001864 case BGP_ATTR_NEXT_HOP:
1865 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1866 break;
1867 case BGP_ATTR_MULTI_EXIT_DISC:
1868 ret = bgp_attr_med (peer, length, attr, flag, startp);
1869 break;
1870 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001871 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001872 break;
1873 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001874 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001875 break;
1876 case BGP_ATTR_AGGREGATOR:
1877 ret = bgp_attr_aggregator (peer, length, attr, flag);
1878 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001879 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001880 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1881 &as4_aggregator,
1882 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001883 break;
paul718e3742002-12-13 20:15:29 +00001884 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001885 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001886 break;
1887 case BGP_ATTR_ORIGINATOR_ID:
1888 ret = bgp_attr_originator_id (peer, length, attr, flag);
1889 break;
1890 case BGP_ATTR_CLUSTER_LIST:
1891 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1892 break;
1893 case BGP_ATTR_MP_REACH_NLRI:
1894 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1895 break;
1896 case BGP_ATTR_MP_UNREACH_NLRI:
1897 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1898 break;
1899 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001900 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001901 break;
1902 default:
1903 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1904 break;
1905 }
Paul Jakmab881c702010-11-23 16:35:42 +00001906
1907 /* If hard error occured immediately return to the caller. */
1908 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001909 {
1910 zlog (peer->log, LOG_WARNING,
1911 "%s: Attribute %s, parse error",
1912 peer->host,
1913 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001914 bgp_notify_send (peer,
1915 BGP_NOTIFY_UPDATE_ERR,
1916 BGP_NOTIFY_UPDATE_MAL_ATTR);
1917 if (as4_path)
1918 aspath_unintern (&as4_path);
1919 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001920 }
Paul Jakmab881c702010-11-23 16:35:42 +00001921 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1922 {
1923
1924 zlog (peer->log, LOG_WARNING,
1925 "%s: Attribute %s, parse error - treating as withdrawal",
1926 peer->host,
1927 LOOKUP (attr_str, type));
1928 if (as4_path)
1929 aspath_unintern (&as4_path);
1930 return ret;
1931 }
1932
paul718e3742002-12-13 20:15:29 +00001933 /* Check the fetched length. */
1934 if (BGP_INPUT_PNT (peer) != attr_endp)
1935 {
1936 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001937 "%s: BGP attribute %s, fetch error",
1938 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001939 bgp_notify_send (peer,
1940 BGP_NOTIFY_UPDATE_ERR,
1941 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001942 if (as4_path)
1943 aspath_unintern (&as4_path);
1944 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001945 }
1946 }
1947
1948 /* Check final read pointer is same as end pointer. */
1949 if (BGP_INPUT_PNT (peer) != endp)
1950 {
1951 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001952 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001953 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001954 bgp_notify_send (peer,
1955 BGP_NOTIFY_UPDATE_ERR,
1956 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001957 if (as4_path)
1958 aspath_unintern (&as4_path);
1959 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001960 }
1961
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001962 /*
1963 * At this place we can see whether we got AS4_PATH and/or
1964 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1965 * We can not do this before we've read all attributes because
1966 * the as4 handling does not say whether AS4_PATH has to be sent
1967 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1968 * in relationship to AGGREGATOR.
1969 * So, to be defensive, we are not relying on any order and read
1970 * all attributes first, including these 32bit ones, and now,
1971 * afterwards, we look what and if something is to be done for as4.
1972 */
Paul Jakmab881c702010-11-23 16:35:42 +00001973 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001974 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001975 {
1976 if (as4_path)
1977 aspath_unintern (&as4_path);
1978 return BGP_ATTR_PARSE_ERROR;
1979 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001980
1981 /* At this stage, we have done all fiddling with as4, and the
1982 * resulting info is in attr->aggregator resp. attr->aspath
1983 * so we can chuck as4_aggregator and as4_path alltogether in
1984 * order to save memory
1985 */
Paul Jakmab881c702010-11-23 16:35:42 +00001986 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001987 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001988 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001989 /* The flag that we got this is still there, but that does not
1990 * do any trouble
1991 */
1992 }
1993 /*
1994 * The "rest" of the code does nothing with as4_aggregator.
1995 * there is no memory attached specifically which is not part
1996 * of the attr.
1997 * so ignoring just means do nothing.
1998 */
1999 /*
2000 * Finally do the checks on the aspath we did not do yet
2001 * because we waited for a potentially synthesized aspath.
2002 */
Paul Jakmab881c702010-11-23 16:35:42 +00002003 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002004 {
Paul Jakmab881c702010-11-23 16:35:42 +00002005 ret = bgp_attr_aspath_check (peer, attr, flag);
2006 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002007 return ret;
2008 }
2009
paul718e3742002-12-13 20:15:29 +00002010 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002011 if (attr->extra && attr->extra->transit)
2012 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002013
Paul Jakmab881c702010-11-23 16:35:42 +00002014 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002015}
2016
2017/* Well-known attribute check. */
2018int
2019bgp_attr_check (struct peer *peer, struct attr *attr)
2020{
2021 u_char type = 0;
2022
2023 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2024 type = BGP_ATTR_ORIGIN;
2025
2026 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2027 type = BGP_ATTR_AS_PATH;
2028
2029 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2030 type = BGP_ATTR_NEXT_HOP;
2031
2032 if (peer_sort (peer) == BGP_PEER_IBGP
2033 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2034 type = BGP_ATTR_LOCAL_PREF;
2035
2036 if (type)
2037 {
2038 zlog (peer->log, LOG_WARNING,
2039 "%s Missing well-known attribute %d.",
2040 peer->host, type);
2041 bgp_notify_send_with_data (peer,
2042 BGP_NOTIFY_UPDATE_ERR,
2043 BGP_NOTIFY_UPDATE_MISS_ATTR,
2044 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002045 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002046 }
Paul Jakmab881c702010-11-23 16:35:42 +00002047 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002048}
2049
2050int stream_put_prefix (struct stream *, struct prefix *);
2051
2052/* Make attribute packet. */
2053bgp_size_t
2054bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2055 struct stream *s, struct attr *attr, struct prefix *p,
2056 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002057 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002058{
paulfe69a502005-09-10 16:55:02 +00002059 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002060 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002061 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002062 int send_as4_path = 0;
2063 int send_as4_aggregator = 0;
2064 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002065
2066 if (! bgp)
2067 bgp = bgp_get_default ();
2068
2069 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002070 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002071
2072 /* Origin attribute. */
2073 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2074 stream_putc (s, BGP_ATTR_ORIGIN);
2075 stream_putc (s, 1);
2076 stream_putc (s, attr->origin);
2077
2078 /* AS path attribute. */
2079
2080 /* If remote-peer is EBGP */
2081 if (peer_sort (peer) == BGP_PEER_EBGP
2082 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002083 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002084 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002085 {
2086 aspath = aspath_dup (attr->aspath);
2087
2088 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2089 {
2090 /* Strip the confed info, and then stuff our path CONFED_ID
2091 on the front */
2092 aspath = aspath_delete_confed_seq (aspath);
2093 aspath = aspath_add_seq (aspath, bgp->confed_id);
2094 }
2095 else
2096 {
2097 aspath = aspath_add_seq (aspath, peer->local_as);
2098 if (peer->change_local_as)
2099 aspath = aspath_add_seq (aspath, peer->change_local_as);
2100 }
2101 }
2102 else if (peer_sort (peer) == BGP_PEER_CONFED)
2103 {
2104 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2105 aspath = aspath_dup (attr->aspath);
2106 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2107 }
2108 else
2109 aspath = attr->aspath;
2110
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002111 /* If peer is not AS4 capable, then:
2112 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2113 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2114 * types are in it (i.e. exclude them if they are there)
2115 * AND do this only if there is at least one asnum > 65535 in the path!
2116 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2117 * all ASnums > 65535 to BGP_AS_TRANS
2118 */
paul718e3742002-12-13 20:15:29 +00002119
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002120 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2121 stream_putc (s, BGP_ATTR_AS_PATH);
2122 aspath_sizep = stream_get_endp (s);
2123 stream_putw (s, 0);
2124 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2125
2126 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2127 * in the path
2128 */
2129 if (!use32bit && aspath_has_as4 (aspath))
2130 send_as4_path = 1; /* we'll do this later, at the correct place */
2131
paul718e3742002-12-13 20:15:29 +00002132 /* Nexthop attribute. */
2133 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2134 {
2135 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2136 stream_putc (s, BGP_ATTR_NEXT_HOP);
2137 stream_putc (s, 4);
2138 if (safi == SAFI_MPLS_VPN)
2139 {
2140 if (attr->nexthop.s_addr == 0)
2141 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2142 else
2143 stream_put_ipv4 (s, attr->nexthop.s_addr);
2144 }
2145 else
2146 stream_put_ipv4 (s, attr->nexthop.s_addr);
2147 }
2148
2149 /* MED attribute. */
2150 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2151 {
2152 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2153 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2154 stream_putc (s, 4);
2155 stream_putl (s, attr->med);
2156 }
2157
2158 /* Local preference. */
2159 if (peer_sort (peer) == BGP_PEER_IBGP ||
2160 peer_sort (peer) == BGP_PEER_CONFED)
2161 {
2162 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2163 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2164 stream_putc (s, 4);
2165 stream_putl (s, attr->local_pref);
2166 }
2167
2168 /* Atomic aggregate. */
2169 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2170 {
2171 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2172 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2173 stream_putc (s, 0);
2174 }
2175
2176 /* Aggregator. */
2177 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2178 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002179 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002180
2181 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002182 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2183 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002184
2185 if (use32bit)
2186 {
2187 /* AS4 capable peer */
2188 stream_putc (s, 8);
2189 stream_putl (s, attr->extra->aggregator_as);
2190 }
2191 else
2192 {
2193 /* 2-byte AS peer */
2194 stream_putc (s, 6);
2195
2196 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2197 if ( attr->extra->aggregator_as > 65535 )
2198 {
2199 stream_putw (s, BGP_AS_TRANS);
2200
2201 /* we have to send AS4_AGGREGATOR, too.
2202 * we'll do that later in order to send attributes in ascending
2203 * order.
2204 */
2205 send_as4_aggregator = 1;
2206 }
2207 else
2208 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2209 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002210 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002211 }
2212
2213 /* Community attribute. */
2214 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2215 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2216 {
2217 if (attr->community->size * 4 > 255)
2218 {
2219 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2220 stream_putc (s, BGP_ATTR_COMMUNITIES);
2221 stream_putw (s, attr->community->size * 4);
2222 }
2223 else
2224 {
2225 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2226 stream_putc (s, BGP_ATTR_COMMUNITIES);
2227 stream_putc (s, attr->community->size * 4);
2228 }
2229 stream_put (s, attr->community->val, attr->community->size * 4);
2230 }
2231
2232 /* Route Reflector. */
2233 if (peer_sort (peer) == BGP_PEER_IBGP
2234 && from
2235 && peer_sort (from) == BGP_PEER_IBGP)
2236 {
2237 /* Originator ID. */
2238 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2239 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2240 stream_putc (s, 4);
2241
2242 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002243 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002244 else
2245 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002246
2247 /* Cluster list. */
2248 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2249 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2250
Paul Jakma9eda90c2007-08-30 13:36:17 +00002251 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002252 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002253 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002254 /* If this peer configuration's parent BGP has cluster_id. */
2255 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2256 stream_put_in_addr (s, &bgp->cluster_id);
2257 else
2258 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002259 stream_put (s, attr->extra->cluster->list,
2260 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002261 }
2262 else
2263 {
2264 stream_putc (s, 4);
2265 /* If this peer configuration's parent BGP has cluster_id. */
2266 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2267 stream_put_in_addr (s, &bgp->cluster_id);
2268 else
2269 stream_put_in_addr (s, &bgp->router_id);
2270 }
2271 }
2272
2273#ifdef HAVE_IPV6
2274 /* If p is IPv6 address put it into attribute. */
2275 if (p->family == AF_INET6)
2276 {
2277 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002278 struct attr_extra *attre = attr->extra;
2279
2280 assert (attr->extra);
2281
paul718e3742002-12-13 20:15:29 +00002282 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2283 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002284 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002285 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002286 stream_putw (s, AFI_IP6); /* AFI */
2287 stream_putc (s, safi); /* SAFI */
2288
Paul Jakmafb982c22007-05-04 20:15:47 +00002289 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002290
Paul Jakmafb982c22007-05-04 20:15:47 +00002291 if (attre->mp_nexthop_len == 16)
2292 stream_put (s, &attre->mp_nexthop_global, 16);
2293 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002294 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002295 stream_put (s, &attre->mp_nexthop_global, 16);
2296 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002297 }
2298
2299 /* SNPA */
2300 stream_putc (s, 0);
2301
paul718e3742002-12-13 20:15:29 +00002302 /* Prefix write. */
2303 stream_put_prefix (s, p);
2304
2305 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002306 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002307 }
2308#endif /* HAVE_IPV6 */
2309
2310 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2311 {
2312 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002313
2314 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2315 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002316 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002317 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002318 stream_putw (s, AFI_IP); /* AFI */
2319 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2320
2321 stream_putc (s, 4);
2322 stream_put_ipv4 (s, attr->nexthop.s_addr);
2323
2324 /* SNPA */
2325 stream_putc (s, 0);
2326
paul718e3742002-12-13 20:15:29 +00002327 /* Prefix write. */
2328 stream_put_prefix (s, p);
2329
2330 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002331 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002332 }
2333
2334 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2335 {
2336 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002337
2338 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2339 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002340 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002341 stream_putc (s, 0); /* Length of this attribute. */
2342 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002343 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002344
2345 stream_putc (s, 12);
2346 stream_putl (s, 0);
2347 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002348 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002349
2350 /* SNPA */
2351 stream_putc (s, 0);
2352
paul718e3742002-12-13 20:15:29 +00002353 /* Tag, RD, Prefix write. */
2354 stream_putc (s, p->prefixlen + 88);
2355 stream_put (s, tag, 3);
2356 stream_put (s, prd->val, 8);
2357 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2358
2359 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002360 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002361 }
2362
2363 /* Extended Communities attribute. */
2364 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2365 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2366 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002367 struct attr_extra *attre = attr->extra;
2368
2369 assert (attre);
2370
2371 if (peer_sort (peer) == BGP_PEER_IBGP
2372 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002373 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002374 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002375 {
2376 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2377 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002378 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002379 }
2380 else
2381 {
2382 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2383 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002384 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002385 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002386 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002387 }
2388 else
2389 {
paul5228ad22004-06-04 17:58:18 +00002390 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002391 int tbit;
2392 int ecom_tr_size = 0;
2393 int i;
2394
Paul Jakmafb982c22007-05-04 20:15:47 +00002395 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002396 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002397 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002398 tbit = *pnt;
2399
2400 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2401 continue;
2402
2403 ecom_tr_size++;
2404 }
2405
2406 if (ecom_tr_size)
2407 {
2408 if (ecom_tr_size * 8 > 255)
2409 {
2410 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2411 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2412 stream_putw (s, ecom_tr_size * 8);
2413 }
2414 else
2415 {
2416 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2417 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2418 stream_putc (s, ecom_tr_size * 8);
2419 }
2420
Paul Jakmafb982c22007-05-04 20:15:47 +00002421 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002422 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002423 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002424 tbit = *pnt;
2425
2426 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2427 continue;
2428
2429 stream_put (s, pnt, 8);
2430 }
2431 }
paul718e3742002-12-13 20:15:29 +00002432 }
paul718e3742002-12-13 20:15:29 +00002433 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002434
2435 if ( send_as4_path )
2436 {
2437 /* If the peer is NOT As4 capable, AND */
2438 /* there are ASnums > 65535 in path THEN
2439 * give out AS4_PATH */
2440
2441 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2442 * path segments!
2443 * Hm, I wonder... confederation things *should* only be at
2444 * the beginning of an aspath, right? Then we should use
2445 * aspath_delete_confed_seq for this, because it is already
2446 * there! (JK)
2447 * Folks, talk to me: what is reasonable here!?
2448 */
2449 aspath = aspath_delete_confed_seq (aspath);
2450
2451 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2452 stream_putc (s, BGP_ATTR_AS4_PATH);
2453 aspath_sizep = stream_get_endp (s);
2454 stream_putw (s, 0);
2455 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2456 }
2457
2458 if (aspath != attr->aspath)
2459 aspath_free (aspath);
2460
2461 if ( send_as4_aggregator )
2462 {
2463 assert (attr->extra);
2464
2465 /* send AS4_AGGREGATOR, at this place */
2466 /* this section of code moved here in order to ensure the correct
2467 * *ascending* order of attributes
2468 */
2469 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2470 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2471 stream_putc (s, 8);
2472 stream_putl (s, attr->extra->aggregator_as);
2473 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2474 }
Paul Jakma41367172007-08-06 15:24:51 +00002475
paul718e3742002-12-13 20:15:29 +00002476 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002477 if (attr->extra && attr->extra->transit)
2478 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002479
2480 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002481 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002482}
2483
2484bgp_size_t
2485bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2486 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002487 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002488{
2489 unsigned long cp;
2490 unsigned long attrlen_pnt;
2491 bgp_size_t size;
2492
paul9985f832005-02-09 15:51:56 +00002493 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002494
2495 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2496 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2497
paul9985f832005-02-09 15:51:56 +00002498 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002499 stream_putc (s, 0); /* Length of this attribute. */
2500
2501 stream_putw (s, family2afi (p->family));
2502
2503 if (safi == SAFI_MPLS_VPN)
2504 {
2505 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002506 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002507
2508 /* prefix. */
2509 stream_putc (s, p->prefixlen + 88);
2510 stream_put (s, tag, 3);
2511 stream_put (s, prd->val, 8);
2512 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2513 }
2514 else
2515 {
2516 /* SAFI */
2517 stream_putc (s, safi);
2518
2519 /* prefix */
2520 stream_put_prefix (s, p);
2521 }
2522
2523 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002524 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002525 stream_putc_at (s, attrlen_pnt, size);
2526
paul9985f832005-02-09 15:51:56 +00002527 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002528}
2529
2530/* Initialization of attribute. */
2531void
paulfe69a502005-09-10 16:55:02 +00002532bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002533{
paul718e3742002-12-13 20:15:29 +00002534 aspath_init ();
2535 attrhash_init ();
2536 community_init ();
2537 ecommunity_init ();
2538 cluster_init ();
2539 transit_init ();
2540}
2541
Chris Caputo228da422009-07-18 05:44:03 +00002542void
2543bgp_attr_finish (void)
2544{
2545 aspath_finish ();
2546 attrhash_finish ();
2547 community_finish ();
2548 ecommunity_finish ();
2549 cluster_finish ();
2550 transit_finish ();
2551}
2552
paul718e3742002-12-13 20:15:29 +00002553/* Make attribute packet. */
2554void
paula3845922003-10-18 01:30:50 +00002555bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2556 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002557{
2558 unsigned long cp;
2559 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002560 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002561 struct aspath *aspath;
2562
2563 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002564 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002565
2566 /* Place holder of length. */
2567 stream_putw (s, 0);
2568
2569 /* Origin attribute. */
2570 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2571 stream_putc (s, BGP_ATTR_ORIGIN);
2572 stream_putc (s, 1);
2573 stream_putc (s, attr->origin);
2574
2575 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002576
2577 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2578 stream_putc (s, BGP_ATTR_AS_PATH);
2579 aspath_lenp = stream_get_endp (s);
2580 stream_putw (s, 0);
2581
2582 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002583
2584 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002585 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2586 if(prefix != NULL
2587#ifdef HAVE_IPV6
2588 && prefix->family != AF_INET6
2589#endif /* HAVE_IPV6 */
2590 )
2591 {
2592 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2593 stream_putc (s, BGP_ATTR_NEXT_HOP);
2594 stream_putc (s, 4);
2595 stream_put_ipv4 (s, attr->nexthop.s_addr);
2596 }
paul718e3742002-12-13 20:15:29 +00002597
2598 /* MED attribute. */
2599 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2600 {
2601 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2602 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2603 stream_putc (s, 4);
2604 stream_putl (s, attr->med);
2605 }
2606
2607 /* Local preference. */
2608 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2609 {
2610 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2611 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2612 stream_putc (s, 4);
2613 stream_putl (s, attr->local_pref);
2614 }
2615
2616 /* Atomic aggregate. */
2617 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2618 {
2619 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2620 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2621 stream_putc (s, 0);
2622 }
2623
2624 /* Aggregator. */
2625 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2626 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002627 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002628 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2629 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002630 stream_putc (s, 8);
2631 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002632 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002633 }
2634
2635 /* Community attribute. */
2636 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2637 {
2638 if (attr->community->size * 4 > 255)
2639 {
2640 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2641 stream_putc (s, BGP_ATTR_COMMUNITIES);
2642 stream_putw (s, attr->community->size * 4);
2643 }
2644 else
2645 {
2646 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2647 stream_putc (s, BGP_ATTR_COMMUNITIES);
2648 stream_putc (s, attr->community->size * 4);
2649 }
2650 stream_put (s, attr->community->val, attr->community->size * 4);
2651 }
2652
paula3845922003-10-18 01:30:50 +00002653#ifdef HAVE_IPV6
2654 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002655 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2656 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002657 {
2658 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002659 struct attr_extra *attre = attr->extra;
2660
paula3845922003-10-18 01:30:50 +00002661 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2662 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002663 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002664
2665 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002666 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002667 stream_putw(s, AFI_IP6); /* AFI */
2668 stream_putc(s, SAFI_UNICAST); /* SAFI */
2669
2670 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002671 stream_putc(s, attre->mp_nexthop_len);
2672 stream_put(s, &attre->mp_nexthop_global, 16);
2673 if (attre->mp_nexthop_len == 32)
2674 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002675
2676 /* SNPA */
2677 stream_putc(s, 0);
2678
2679 /* Prefix */
2680 stream_put_prefix(s, prefix);
2681
2682 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002683 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002684 }
2685#endif /* HAVE_IPV6 */
2686
paul718e3742002-12-13 20:15:29 +00002687 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002688 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002689 stream_putw_at (s, cp, len);
2690}