blob: aa4ce8f1e2353fb80736f118d3cacd01819e9896 [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);
1791 flag = stream_getc (BGP_INPUT (peer));
1792 type = stream_getc (BGP_INPUT (peer));
1793
Paul Jakma370b64a2007-12-22 16:49:52 +00001794 /* Check whether Extended-Length applies and is in bounds */
1795 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1796 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1797 {
1798 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001799 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001800 peer->host,
1801 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1802
1803 bgp_notify_send (peer,
1804 BGP_NOTIFY_UPDATE_ERR,
1805 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001806 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001807 }
1808
paul718e3742002-12-13 20:15:29 +00001809 /* Check extended attribue length bit. */
1810 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1811 length = stream_getw (BGP_INPUT (peer));
1812 else
1813 length = stream_getc (BGP_INPUT (peer));
1814
1815 /* If any attribute appears more than once in the UPDATE
1816 message, then the Error Subcode is set to Malformed Attribute
1817 List. */
1818
1819 if (CHECK_BITMAP (seen, type))
1820 {
1821 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001822 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001823 peer->host, type);
1824
1825 bgp_notify_send (peer,
1826 BGP_NOTIFY_UPDATE_ERR,
1827 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001828 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001829 }
1830
1831 /* Set type to bitmap to check duplicate attribute. `type' is
1832 unsigned char so it never overflow bitmap range. */
1833
1834 SET_BITMAP (seen, type);
1835
1836 /* Overflow check. */
1837 attr_endp = BGP_INPUT_PNT (peer) + length;
1838
1839 if (attr_endp > endp)
1840 {
1841 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001842 "%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 +00001843 bgp_notify_send (peer,
1844 BGP_NOTIFY_UPDATE_ERR,
1845 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001846 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001847 }
1848
1849 /* OK check attribute and store it's value. */
1850 switch (type)
1851 {
1852 case BGP_ATTR_ORIGIN:
1853 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1854 break;
1855 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001856 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001857 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001858 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001859 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001860 break;
paul718e3742002-12-13 20:15:29 +00001861 case BGP_ATTR_NEXT_HOP:
1862 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1863 break;
1864 case BGP_ATTR_MULTI_EXIT_DISC:
1865 ret = bgp_attr_med (peer, length, attr, flag, startp);
1866 break;
1867 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001868 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001869 break;
1870 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001871 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001872 break;
1873 case BGP_ATTR_AGGREGATOR:
1874 ret = bgp_attr_aggregator (peer, length, attr, flag);
1875 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001876 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001877 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1878 &as4_aggregator,
1879 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001880 break;
paul718e3742002-12-13 20:15:29 +00001881 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001882 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001883 break;
1884 case BGP_ATTR_ORIGINATOR_ID:
1885 ret = bgp_attr_originator_id (peer, length, attr, flag);
1886 break;
1887 case BGP_ATTR_CLUSTER_LIST:
1888 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1889 break;
1890 case BGP_ATTR_MP_REACH_NLRI:
1891 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1892 break;
1893 case BGP_ATTR_MP_UNREACH_NLRI:
1894 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1895 break;
1896 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001897 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001898 break;
1899 default:
1900 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1901 break;
1902 }
Paul Jakmab881c702010-11-23 16:35:42 +00001903
1904 /* If hard error occured immediately return to the caller. */
1905 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001906 {
1907 zlog (peer->log, LOG_WARNING,
1908 "%s: Attribute %s, parse error",
1909 peer->host,
1910 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001911 bgp_notify_send (peer,
1912 BGP_NOTIFY_UPDATE_ERR,
1913 BGP_NOTIFY_UPDATE_MAL_ATTR);
1914 if (as4_path)
1915 aspath_unintern (&as4_path);
1916 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001917 }
Paul Jakmab881c702010-11-23 16:35:42 +00001918 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1919 {
1920
1921 zlog (peer->log, LOG_WARNING,
1922 "%s: Attribute %s, parse error - treating as withdrawal",
1923 peer->host,
1924 LOOKUP (attr_str, type));
1925 if (as4_path)
1926 aspath_unintern (&as4_path);
1927 return ret;
1928 }
1929
paul718e3742002-12-13 20:15:29 +00001930 /* Check the fetched length. */
1931 if (BGP_INPUT_PNT (peer) != attr_endp)
1932 {
1933 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001934 "%s: BGP attribute %s, fetch error",
1935 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001936 bgp_notify_send (peer,
1937 BGP_NOTIFY_UPDATE_ERR,
1938 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001939 if (as4_path)
1940 aspath_unintern (&as4_path);
1941 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001942 }
1943 }
1944
1945 /* Check final read pointer is same as end pointer. */
1946 if (BGP_INPUT_PNT (peer) != endp)
1947 {
1948 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001949 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001950 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001951 bgp_notify_send (peer,
1952 BGP_NOTIFY_UPDATE_ERR,
1953 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001954 if (as4_path)
1955 aspath_unintern (&as4_path);
1956 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001957 }
1958
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001959 /*
1960 * At this place we can see whether we got AS4_PATH and/or
1961 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1962 * We can not do this before we've read all attributes because
1963 * the as4 handling does not say whether AS4_PATH has to be sent
1964 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1965 * in relationship to AGGREGATOR.
1966 * So, to be defensive, we are not relying on any order and read
1967 * all attributes first, including these 32bit ones, and now,
1968 * afterwards, we look what and if something is to be done for as4.
1969 */
Paul Jakmab881c702010-11-23 16:35:42 +00001970 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001971 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001972 {
1973 if (as4_path)
1974 aspath_unintern (&as4_path);
1975 return BGP_ATTR_PARSE_ERROR;
1976 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001977
1978 /* At this stage, we have done all fiddling with as4, and the
1979 * resulting info is in attr->aggregator resp. attr->aspath
1980 * so we can chuck as4_aggregator and as4_path alltogether in
1981 * order to save memory
1982 */
Paul Jakmab881c702010-11-23 16:35:42 +00001983 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001984 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001985 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001986 /* The flag that we got this is still there, but that does not
1987 * do any trouble
1988 */
1989 }
1990 /*
1991 * The "rest" of the code does nothing with as4_aggregator.
1992 * there is no memory attached specifically which is not part
1993 * of the attr.
1994 * so ignoring just means do nothing.
1995 */
1996 /*
1997 * Finally do the checks on the aspath we did not do yet
1998 * because we waited for a potentially synthesized aspath.
1999 */
Paul Jakmab881c702010-11-23 16:35:42 +00002000 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002001 {
Paul Jakmab881c702010-11-23 16:35:42 +00002002 ret = bgp_attr_aspath_check (peer, attr, flag);
2003 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002004 return ret;
2005 }
2006
paul718e3742002-12-13 20:15:29 +00002007 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002008 if (attr->extra && attr->extra->transit)
2009 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002010
Paul Jakmab881c702010-11-23 16:35:42 +00002011 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002012}
2013
2014/* Well-known attribute check. */
2015int
2016bgp_attr_check (struct peer *peer, struct attr *attr)
2017{
2018 u_char type = 0;
2019
2020 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2021 type = BGP_ATTR_ORIGIN;
2022
2023 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2024 type = BGP_ATTR_AS_PATH;
2025
2026 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2027 type = BGP_ATTR_NEXT_HOP;
2028
2029 if (peer_sort (peer) == BGP_PEER_IBGP
2030 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2031 type = BGP_ATTR_LOCAL_PREF;
2032
2033 if (type)
2034 {
2035 zlog (peer->log, LOG_WARNING,
2036 "%s Missing well-known attribute %d.",
2037 peer->host, type);
2038 bgp_notify_send_with_data (peer,
2039 BGP_NOTIFY_UPDATE_ERR,
2040 BGP_NOTIFY_UPDATE_MISS_ATTR,
2041 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002042 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002043 }
Paul Jakmab881c702010-11-23 16:35:42 +00002044 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002045}
2046
2047int stream_put_prefix (struct stream *, struct prefix *);
2048
2049/* Make attribute packet. */
2050bgp_size_t
2051bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2052 struct stream *s, struct attr *attr, struct prefix *p,
2053 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002054 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002055{
paulfe69a502005-09-10 16:55:02 +00002056 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002057 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002058 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002059 int send_as4_path = 0;
2060 int send_as4_aggregator = 0;
2061 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002062
2063 if (! bgp)
2064 bgp = bgp_get_default ();
2065
2066 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002067 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002068
2069 /* Origin attribute. */
2070 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2071 stream_putc (s, BGP_ATTR_ORIGIN);
2072 stream_putc (s, 1);
2073 stream_putc (s, attr->origin);
2074
2075 /* AS path attribute. */
2076
2077 /* If remote-peer is EBGP */
2078 if (peer_sort (peer) == BGP_PEER_EBGP
2079 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002080 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002081 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002082 {
2083 aspath = aspath_dup (attr->aspath);
2084
2085 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2086 {
2087 /* Strip the confed info, and then stuff our path CONFED_ID
2088 on the front */
2089 aspath = aspath_delete_confed_seq (aspath);
2090 aspath = aspath_add_seq (aspath, bgp->confed_id);
2091 }
2092 else
2093 {
2094 aspath = aspath_add_seq (aspath, peer->local_as);
2095 if (peer->change_local_as)
2096 aspath = aspath_add_seq (aspath, peer->change_local_as);
2097 }
2098 }
2099 else if (peer_sort (peer) == BGP_PEER_CONFED)
2100 {
2101 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2102 aspath = aspath_dup (attr->aspath);
2103 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2104 }
2105 else
2106 aspath = attr->aspath;
2107
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002108 /* If peer is not AS4 capable, then:
2109 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2110 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2111 * types are in it (i.e. exclude them if they are there)
2112 * AND do this only if there is at least one asnum > 65535 in the path!
2113 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2114 * all ASnums > 65535 to BGP_AS_TRANS
2115 */
paul718e3742002-12-13 20:15:29 +00002116
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002117 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2118 stream_putc (s, BGP_ATTR_AS_PATH);
2119 aspath_sizep = stream_get_endp (s);
2120 stream_putw (s, 0);
2121 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2122
2123 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2124 * in the path
2125 */
2126 if (!use32bit && aspath_has_as4 (aspath))
2127 send_as4_path = 1; /* we'll do this later, at the correct place */
2128
paul718e3742002-12-13 20:15:29 +00002129 /* Nexthop attribute. */
2130 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2131 {
2132 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2133 stream_putc (s, BGP_ATTR_NEXT_HOP);
2134 stream_putc (s, 4);
2135 if (safi == SAFI_MPLS_VPN)
2136 {
2137 if (attr->nexthop.s_addr == 0)
2138 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2139 else
2140 stream_put_ipv4 (s, attr->nexthop.s_addr);
2141 }
2142 else
2143 stream_put_ipv4 (s, attr->nexthop.s_addr);
2144 }
2145
2146 /* MED attribute. */
2147 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2148 {
2149 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2150 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2151 stream_putc (s, 4);
2152 stream_putl (s, attr->med);
2153 }
2154
2155 /* Local preference. */
2156 if (peer_sort (peer) == BGP_PEER_IBGP ||
2157 peer_sort (peer) == BGP_PEER_CONFED)
2158 {
2159 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2160 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2161 stream_putc (s, 4);
2162 stream_putl (s, attr->local_pref);
2163 }
2164
2165 /* Atomic aggregate. */
2166 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2167 {
2168 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2169 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2170 stream_putc (s, 0);
2171 }
2172
2173 /* Aggregator. */
2174 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2175 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002176 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002177
2178 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002179 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2180 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002181
2182 if (use32bit)
2183 {
2184 /* AS4 capable peer */
2185 stream_putc (s, 8);
2186 stream_putl (s, attr->extra->aggregator_as);
2187 }
2188 else
2189 {
2190 /* 2-byte AS peer */
2191 stream_putc (s, 6);
2192
2193 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2194 if ( attr->extra->aggregator_as > 65535 )
2195 {
2196 stream_putw (s, BGP_AS_TRANS);
2197
2198 /* we have to send AS4_AGGREGATOR, too.
2199 * we'll do that later in order to send attributes in ascending
2200 * order.
2201 */
2202 send_as4_aggregator = 1;
2203 }
2204 else
2205 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2206 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002207 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002208 }
2209
2210 /* Community attribute. */
2211 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2212 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2213 {
2214 if (attr->community->size * 4 > 255)
2215 {
2216 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2217 stream_putc (s, BGP_ATTR_COMMUNITIES);
2218 stream_putw (s, attr->community->size * 4);
2219 }
2220 else
2221 {
2222 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2223 stream_putc (s, BGP_ATTR_COMMUNITIES);
2224 stream_putc (s, attr->community->size * 4);
2225 }
2226 stream_put (s, attr->community->val, attr->community->size * 4);
2227 }
2228
2229 /* Route Reflector. */
2230 if (peer_sort (peer) == BGP_PEER_IBGP
2231 && from
2232 && peer_sort (from) == BGP_PEER_IBGP)
2233 {
2234 /* Originator ID. */
2235 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2236 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2237 stream_putc (s, 4);
2238
2239 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002240 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002241 else
2242 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002243
2244 /* Cluster list. */
2245 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2246 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2247
Paul Jakma9eda90c2007-08-30 13:36:17 +00002248 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002249 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002250 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002251 /* If this peer configuration's parent BGP has cluster_id. */
2252 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2253 stream_put_in_addr (s, &bgp->cluster_id);
2254 else
2255 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002256 stream_put (s, attr->extra->cluster->list,
2257 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002258 }
2259 else
2260 {
2261 stream_putc (s, 4);
2262 /* If this peer configuration's parent BGP has cluster_id. */
2263 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2264 stream_put_in_addr (s, &bgp->cluster_id);
2265 else
2266 stream_put_in_addr (s, &bgp->router_id);
2267 }
2268 }
2269
2270#ifdef HAVE_IPV6
2271 /* If p is IPv6 address put it into attribute. */
2272 if (p->family == AF_INET6)
2273 {
2274 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002275 struct attr_extra *attre = attr->extra;
2276
2277 assert (attr->extra);
2278
paul718e3742002-12-13 20:15:29 +00002279 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2280 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002281 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002282 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002283 stream_putw (s, AFI_IP6); /* AFI */
2284 stream_putc (s, safi); /* SAFI */
2285
Paul Jakmafb982c22007-05-04 20:15:47 +00002286 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002287
Paul Jakmafb982c22007-05-04 20:15:47 +00002288 if (attre->mp_nexthop_len == 16)
2289 stream_put (s, &attre->mp_nexthop_global, 16);
2290 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002291 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002292 stream_put (s, &attre->mp_nexthop_global, 16);
2293 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002294 }
2295
2296 /* SNPA */
2297 stream_putc (s, 0);
2298
paul718e3742002-12-13 20:15:29 +00002299 /* Prefix write. */
2300 stream_put_prefix (s, p);
2301
2302 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002303 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002304 }
2305#endif /* HAVE_IPV6 */
2306
2307 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2308 {
2309 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002310
2311 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2312 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002313 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002314 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002315 stream_putw (s, AFI_IP); /* AFI */
2316 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2317
2318 stream_putc (s, 4);
2319 stream_put_ipv4 (s, attr->nexthop.s_addr);
2320
2321 /* SNPA */
2322 stream_putc (s, 0);
2323
paul718e3742002-12-13 20:15:29 +00002324 /* Prefix write. */
2325 stream_put_prefix (s, p);
2326
2327 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002328 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002329 }
2330
2331 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2332 {
2333 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002334
2335 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2336 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002337 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002338 stream_putc (s, 0); /* Length of this attribute. */
2339 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002340 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002341
2342 stream_putc (s, 12);
2343 stream_putl (s, 0);
2344 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002345 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002346
2347 /* SNPA */
2348 stream_putc (s, 0);
2349
paul718e3742002-12-13 20:15:29 +00002350 /* Tag, RD, Prefix write. */
2351 stream_putc (s, p->prefixlen + 88);
2352 stream_put (s, tag, 3);
2353 stream_put (s, prd->val, 8);
2354 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2355
2356 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002357 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002358 }
2359
2360 /* Extended Communities attribute. */
2361 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2362 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2363 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002364 struct attr_extra *attre = attr->extra;
2365
2366 assert (attre);
2367
2368 if (peer_sort (peer) == BGP_PEER_IBGP
2369 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002370 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002371 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002372 {
2373 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2374 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002375 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002376 }
2377 else
2378 {
2379 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2380 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002381 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002382 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002384 }
2385 else
2386 {
paul5228ad22004-06-04 17:58:18 +00002387 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002388 int tbit;
2389 int ecom_tr_size = 0;
2390 int i;
2391
Paul Jakmafb982c22007-05-04 20:15:47 +00002392 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002393 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002394 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002395 tbit = *pnt;
2396
2397 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2398 continue;
2399
2400 ecom_tr_size++;
2401 }
2402
2403 if (ecom_tr_size)
2404 {
2405 if (ecom_tr_size * 8 > 255)
2406 {
2407 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2408 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2409 stream_putw (s, ecom_tr_size * 8);
2410 }
2411 else
2412 {
2413 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2414 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2415 stream_putc (s, ecom_tr_size * 8);
2416 }
2417
Paul Jakmafb982c22007-05-04 20:15:47 +00002418 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002419 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002420 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002421 tbit = *pnt;
2422
2423 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2424 continue;
2425
2426 stream_put (s, pnt, 8);
2427 }
2428 }
paul718e3742002-12-13 20:15:29 +00002429 }
paul718e3742002-12-13 20:15:29 +00002430 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002431
2432 if ( send_as4_path )
2433 {
2434 /* If the peer is NOT As4 capable, AND */
2435 /* there are ASnums > 65535 in path THEN
2436 * give out AS4_PATH */
2437
2438 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2439 * path segments!
2440 * Hm, I wonder... confederation things *should* only be at
2441 * the beginning of an aspath, right? Then we should use
2442 * aspath_delete_confed_seq for this, because it is already
2443 * there! (JK)
2444 * Folks, talk to me: what is reasonable here!?
2445 */
2446 aspath = aspath_delete_confed_seq (aspath);
2447
2448 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2449 stream_putc (s, BGP_ATTR_AS4_PATH);
2450 aspath_sizep = stream_get_endp (s);
2451 stream_putw (s, 0);
2452 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2453 }
2454
2455 if (aspath != attr->aspath)
2456 aspath_free (aspath);
2457
2458 if ( send_as4_aggregator )
2459 {
2460 assert (attr->extra);
2461
2462 /* send AS4_AGGREGATOR, at this place */
2463 /* this section of code moved here in order to ensure the correct
2464 * *ascending* order of attributes
2465 */
2466 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2467 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2468 stream_putc (s, 8);
2469 stream_putl (s, attr->extra->aggregator_as);
2470 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2471 }
Paul Jakma41367172007-08-06 15:24:51 +00002472
paul718e3742002-12-13 20:15:29 +00002473 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002474 if (attr->extra && attr->extra->transit)
2475 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002476
2477 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002478 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002479}
2480
2481bgp_size_t
2482bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2483 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002484 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002485{
2486 unsigned long cp;
2487 unsigned long attrlen_pnt;
2488 bgp_size_t size;
2489
paul9985f832005-02-09 15:51:56 +00002490 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002491
2492 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2493 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2494
paul9985f832005-02-09 15:51:56 +00002495 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002496 stream_putc (s, 0); /* Length of this attribute. */
2497
2498 stream_putw (s, family2afi (p->family));
2499
2500 if (safi == SAFI_MPLS_VPN)
2501 {
2502 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002503 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002504
2505 /* prefix. */
2506 stream_putc (s, p->prefixlen + 88);
2507 stream_put (s, tag, 3);
2508 stream_put (s, prd->val, 8);
2509 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2510 }
2511 else
2512 {
2513 /* SAFI */
2514 stream_putc (s, safi);
2515
2516 /* prefix */
2517 stream_put_prefix (s, p);
2518 }
2519
2520 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002521 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002522 stream_putc_at (s, attrlen_pnt, size);
2523
paul9985f832005-02-09 15:51:56 +00002524 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002525}
2526
2527/* Initialization of attribute. */
2528void
paulfe69a502005-09-10 16:55:02 +00002529bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002530{
paul718e3742002-12-13 20:15:29 +00002531 aspath_init ();
2532 attrhash_init ();
2533 community_init ();
2534 ecommunity_init ();
2535 cluster_init ();
2536 transit_init ();
2537}
2538
Chris Caputo228da422009-07-18 05:44:03 +00002539void
2540bgp_attr_finish (void)
2541{
2542 aspath_finish ();
2543 attrhash_finish ();
2544 community_finish ();
2545 ecommunity_finish ();
2546 cluster_finish ();
2547 transit_finish ();
2548}
2549
paul718e3742002-12-13 20:15:29 +00002550/* Make attribute packet. */
2551void
paula3845922003-10-18 01:30:50 +00002552bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2553 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002554{
2555 unsigned long cp;
2556 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002557 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002558 struct aspath *aspath;
2559
2560 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002561 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002562
2563 /* Place holder of length. */
2564 stream_putw (s, 0);
2565
2566 /* Origin attribute. */
2567 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2568 stream_putc (s, BGP_ATTR_ORIGIN);
2569 stream_putc (s, 1);
2570 stream_putc (s, attr->origin);
2571
2572 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002573
2574 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2575 stream_putc (s, BGP_ATTR_AS_PATH);
2576 aspath_lenp = stream_get_endp (s);
2577 stream_putw (s, 0);
2578
2579 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002580
2581 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002582 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2583 if(prefix != NULL
2584#ifdef HAVE_IPV6
2585 && prefix->family != AF_INET6
2586#endif /* HAVE_IPV6 */
2587 )
2588 {
2589 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2590 stream_putc (s, BGP_ATTR_NEXT_HOP);
2591 stream_putc (s, 4);
2592 stream_put_ipv4 (s, attr->nexthop.s_addr);
2593 }
paul718e3742002-12-13 20:15:29 +00002594
2595 /* MED attribute. */
2596 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2597 {
2598 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2599 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2600 stream_putc (s, 4);
2601 stream_putl (s, attr->med);
2602 }
2603
2604 /* Local preference. */
2605 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2606 {
2607 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2608 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2609 stream_putc (s, 4);
2610 stream_putl (s, attr->local_pref);
2611 }
2612
2613 /* Atomic aggregate. */
2614 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2615 {
2616 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2617 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2618 stream_putc (s, 0);
2619 }
2620
2621 /* Aggregator. */
2622 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2623 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002624 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002625 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2626 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002627 stream_putc (s, 8);
2628 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002629 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002630 }
2631
2632 /* Community attribute. */
2633 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2634 {
2635 if (attr->community->size * 4 > 255)
2636 {
2637 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2638 stream_putc (s, BGP_ATTR_COMMUNITIES);
2639 stream_putw (s, attr->community->size * 4);
2640 }
2641 else
2642 {
2643 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2644 stream_putc (s, BGP_ATTR_COMMUNITIES);
2645 stream_putc (s, attr->community->size * 4);
2646 }
2647 stream_put (s, attr->community->val, attr->community->size * 4);
2648 }
2649
paula3845922003-10-18 01:30:50 +00002650#ifdef HAVE_IPV6
2651 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002652 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2653 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002654 {
2655 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002656 struct attr_extra *attre = attr->extra;
2657
paula3845922003-10-18 01:30:50 +00002658 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2659 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002660 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002661
2662 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002663 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002664 stream_putw(s, AFI_IP6); /* AFI */
2665 stream_putc(s, SAFI_UNICAST); /* SAFI */
2666
2667 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002668 stream_putc(s, attre->mp_nexthop_len);
2669 stream_put(s, &attre->mp_nexthop_global, 16);
2670 if (attre->mp_nexthop_len == 32)
2671 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002672
2673 /* SNPA */
2674 stream_putc(s, 0);
2675
2676 /* Prefix */
2677 stream_put_prefix(s, prefix);
2678
2679 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002680 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002681 }
2682#endif /* HAVE_IPV6 */
2683
paul718e3742002-12-13 20:15:29 +00002684 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002685 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002686 stream_putw_at (s, cp, len);
2687}