blob: d43c104f9505e9b860f6b25bc84866efbbb2d46e [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). */
776 if (flag != BGP_ATTR_FLAG_TRANS)
777 {
778 zlog (peer->log, LOG_ERR,
779 "Origin attribute flag isn't transitive %d", 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 }
784
785 /* If any recognized attribute has Attribute Length that conflicts
786 with the expected length (based on the attribute type code), then
787 the Error Subcode is set to Attribute Length Error. The Data
788 field contains the erroneous attribute (type, length and
789 value). */
790 if (length != 1)
791 {
792 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
793 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000794 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
795 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
796 startp, total);
paul718e3742002-12-13 20:15:29 +0000797 }
798
799 /* Fetch origin attribute. */
800 attr->origin = stream_getc (BGP_INPUT (peer));
801
802 /* If the ORIGIN attribute has an undefined value, then the Error
803 Subcode is set to Invalid Origin Attribute. The Data field
804 contains the unrecognized attribute (type, length and value). */
805 if ((attr->origin != BGP_ORIGIN_IGP)
806 && (attr->origin != BGP_ORIGIN_EGP)
807 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
808 {
809 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
810 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000811 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
812 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
813 startp, total);
paul718e3742002-12-13 20:15:29 +0000814 }
815
816 /* Set oring attribute flag. */
817 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
818
819 return 0;
820}
Paul Jakmaab005292010-11-27 22:48:34 +0000821
822/* Parse AS path information. This function is wrapper of
823 aspath_parse. */
824static int
paul718e3742002-12-13 20:15:29 +0000825bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000826 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000827{
Paul Jakmaab005292010-11-27 22:48:34 +0000828 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000829
Paul Jakmaab005292010-11-27 22:48:34 +0000830 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000831
Paul Jakmaab005292010-11-27 22:48:34 +0000832 /* Flag check. */
833 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
834 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000835 {
836 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000837 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000838 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
839 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
840 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400841 }
Paul Jakmaab005292010-11-27 22:48:34 +0000842
843 /*
844 * peer with AS4 => will get 4Byte ASnums
845 * otherwise, will get 16 Bit
846 */
847 attr->aspath = aspath_parse (peer->ibuf, length,
848 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
849
850 /* In case of IBGP, length will be zero. */
851 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000852 {
Paul Jakmab881c702010-11-23 16:35:42 +0000853 zlog (peer->log, LOG_ERR,
854 "Malformed AS path from %s, length is %d",
855 peer->host, length);
856 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
857 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
858 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000859 }
Chris Hallcddb8112010-08-09 22:31:37 +0400860
Paul Jakmaab005292010-11-27 22:48:34 +0000861 /* Set aspath attribute flag. */
862 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000863
Paul Jakmab881c702010-11-23 16:35:42 +0000864 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000865}
866
Paul Jakmab881c702010-11-23 16:35:42 +0000867static bgp_attr_parse_ret_t
868bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000869{
870 /* These checks were part of bgp_attr_aspath, but with
871 * as4 we should to check aspath things when
872 * aspath synthesizing with as4_path has already taken place.
873 * Otherwise we check ASPATH and use the synthesized thing, and that is
874 * not right.
875 * So do the checks later, i.e. here
876 */
877 struct bgp *bgp = peer->bgp;
878 struct aspath *aspath;
879
paul718e3742002-12-13 20:15:29 +0000880 bgp = peer->bgp;
881
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300882 /* Confederation sanity check. */
883 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
884 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
885 {
886 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000887 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
888 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
889 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300890 }
891
paul718e3742002-12-13 20:15:29 +0000892 /* First AS check for EBGP. */
893 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
894 {
895 if (peer_sort (peer) == BGP_PEER_EBGP
896 && ! aspath_firstas_check (attr->aspath, peer->as))
897 {
898 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400899 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000900 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
901 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
902 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000903 }
904 }
905
906 /* local-as prepend */
907 if (peer->change_local_as &&
908 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
909 {
910 aspath = aspath_dup (attr->aspath);
911 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000912 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000913 attr->aspath = aspath_intern (aspath);
914 }
915
Paul Jakmab881c702010-11-23 16:35:42 +0000916 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000917}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000918
Paul Jakmaab005292010-11-27 22:48:34 +0000919/* Parse AS4 path information. This function is another wrapper of
920 aspath_parse. */
921static int
Paul Jakmab881c702010-11-23 16:35:42 +0000922bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
923 struct attr *attr, u_char flag, u_char *startp,
924 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000925{
Paul Jakmab881c702010-11-23 16:35:42 +0000926 bgp_size_t total;
927
928 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
929
930 /* Flag check. */
931 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
932 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
933 {
934 zlog (peer->log, LOG_ERR,
935 "As4-Path attribute flag isn't optional/transitive %d", flag);
936 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
937 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
938 startp, total);
939 }
940
Paul Jakmaab005292010-11-27 22:48:34 +0000941 *as4_path = aspath_parse (peer->ibuf, length, 1);
942
Paul Jakmab881c702010-11-23 16:35:42 +0000943 /* In case of IBGP, length will be zero. */
944 if (!*as4_path)
945 {
946 zlog (peer->log, LOG_ERR,
947 "Malformed AS4 path from %s, length is %d",
948 peer->host, length);
949 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
950 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
951 NULL, 0);
952 }
953
Paul Jakmaab005292010-11-27 22:48:34 +0000954 /* Set aspath attribute flag. */
955 if (as4_path)
956 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
957
Paul Jakmab881c702010-11-23 16:35:42 +0000958 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000959}
960
paul718e3742002-12-13 20:15:29 +0000961/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000962static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000963bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
964 struct attr *attr, u_char flag, u_char *startp)
965{
966 bgp_size_t total;
967
968 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
969
970 /* Flag check. */
971 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
972 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
973 {
974 zlog (peer->log, LOG_ERR,
975 "Origin attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000976 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
977 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
978 startp, total);
paul718e3742002-12-13 20:15:29 +0000979 }
980
981 /* Check nexthop attribute length. */
982 if (length != 4)
983 {
984 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
985 length);
986
Paul Jakmab881c702010-11-23 16:35:42 +0000987 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
988 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
989 startp, total);
paul718e3742002-12-13 20:15:29 +0000990 }
991
992 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
993 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
994
Paul Jakmab881c702010-11-23 16:35:42 +0000995 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +0000996}
997
998/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000999static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001000bgp_attr_med (struct peer *peer, bgp_size_t length,
1001 struct attr *attr, u_char flag, u_char *startp)
1002{
1003 bgp_size_t total;
1004
1005 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1006
1007 /* Length check. */
1008 if (length != 4)
1009 {
1010 zlog (peer->log, LOG_ERR,
1011 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001012
1013 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1014 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1015 startp, total);
paul718e3742002-12-13 20:15:29 +00001016 }
1017
1018 attr->med = stream_getl (peer->ibuf);
1019
1020 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1021
Paul Jakmab881c702010-11-23 16:35:42 +00001022 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001023}
1024
1025/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001026static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001027bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
1028 struct attr *attr, u_char flag)
1029{
1030 /* If it is contained in an UPDATE message that is received from an
1031 external peer, then this attribute MUST be ignored by the
1032 receiving speaker. */
1033 if (peer_sort (peer) == BGP_PEER_EBGP)
1034 {
paul9985f832005-02-09 15:51:56 +00001035 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001036 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001037 }
1038
1039 if (length == 4)
1040 attr->local_pref = stream_getl (peer->ibuf);
1041 else
1042 attr->local_pref = 0;
1043
1044 /* Set atomic aggregate flag. */
1045 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1046
Paul Jakmab881c702010-11-23 16:35:42 +00001047 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001048}
1049
1050/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001051static int
paul718e3742002-12-13 20:15:29 +00001052bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1053 struct attr *attr, u_char flag)
1054{
1055 if (length != 0)
1056 {
1057 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1058
Paul Jakmab881c702010-11-23 16:35:42 +00001059 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1060 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1061 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001062 }
1063
1064 /* Set atomic aggregate flag. */
1065 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1066
Paul Jakmab881c702010-11-23 16:35:42 +00001067 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001068}
1069
1070/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001071static int
paul718e3742002-12-13 20:15:29 +00001072bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1073 struct attr *attr, u_char flag)
1074{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001075 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001076 struct attr_extra *attre = bgp_attr_extra_get (attr);
1077
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001078 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001079 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001080 wantedlen = 8;
1081
1082 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001083 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001084 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001085
Paul Jakmab881c702010-11-23 16:35:42 +00001086 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1087 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1088 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001089 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001090
1091 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1092 attre->aggregator_as = stream_getl (peer->ibuf);
1093 else
1094 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001095 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001096
1097 /* Set atomic aggregate flag. */
1098 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1099
Paul Jakmab881c702010-11-23 16:35:42 +00001100 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001101}
1102
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001103/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001104static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001105bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001106 struct attr *attr, u_char flag,
1107 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001108 struct in_addr *as4_aggregator_addr)
1109{
1110 if (length != 8)
1111 {
1112 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001113 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1114 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1115 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001116 }
1117 *as4_aggregator_as = stream_getl (peer->ibuf);
1118 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1119
1120 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1121
Paul Jakmab881c702010-11-23 16:35:42 +00001122 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001123}
1124
1125/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1126 */
Paul Jakmab881c702010-11-23 16:35:42 +00001127static bgp_attr_parse_ret_t
1128bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001129 struct aspath *as4_path, as_t as4_aggregator,
1130 struct in_addr *as4_aggregator_addr)
1131{
1132 int ignore_as4_path = 0;
1133 struct aspath *newpath;
1134 struct attr_extra *attre = attr->extra;
1135
Paul Jakmab881c702010-11-23 16:35:42 +00001136 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001137 {
1138 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1139 * if given.
1140 * It is worth a warning though, because the peer really
1141 * should not send them
1142 */
1143 if (BGP_DEBUG(as4, AS4))
1144 {
1145 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1146 zlog_debug ("[AS4] %s %s AS4_PATH",
1147 peer->host, "AS4 capable peer, yet it sent");
1148
1149 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1150 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1151 peer->host, "AS4 capable peer, yet it sent");
1152 }
1153
Paul Jakmab881c702010-11-23 16:35:42 +00001154 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001155 }
1156
Paul Jakmab881c702010-11-23 16:35:42 +00001157 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1158 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001159 {
1160 /* Hu? This is not supposed to happen at all!
1161 * got as4_path and no aspath,
1162 * This should already
1163 * have been handled by 'well known attributes missing'
1164 * But... yeah, paranoia
1165 * Take this as a "malformed attribute"
1166 */
1167 zlog (peer->log, LOG_ERR,
1168 "%s BGP not AS4 capable peer sent AS4_PATH but"
1169 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001170 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1171 BGP_NOTIFY_UPDATE_MAL_ATTR,
1172 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001173 }
1174
1175 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1176 * because that may override AS4_PATH
1177 */
1178 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1179 {
Paul Jakmab881c702010-11-23 16:35:42 +00001180 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001181 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001182 assert (attre);
1183
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001184 /* received both.
1185 * if the as_number in aggregator is not AS_TRANS,
1186 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1187 * and the Aggregator shall be taken as
1188 * info on the aggregating node, and the AS_PATH
1189 * shall be taken as the AS_PATH
1190 * otherwise
1191 * the Aggregator shall be ignored and the
1192 * AS4_AGGREGATOR shall be taken as the
1193 * Aggregating node and the AS_PATH is to be
1194 * constructed "as in all other cases"
1195 */
Paul Jakmab881c702010-11-23 16:35:42 +00001196 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001197 {
1198 /* ignore */
1199 if ( BGP_DEBUG(as4, AS4))
1200 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1201 " send AGGREGATOR != AS_TRANS and"
1202 " AS4_AGGREGATOR, so ignore"
1203 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1204 ignore_as4_path = 1;
1205 }
1206 else
1207 {
1208 /* "New_aggregator shall be taken as aggregator" */
1209 attre->aggregator_as = as4_aggregator;
1210 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1211 }
1212 }
1213 else
1214 {
1215 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1216 * That is bogus - but reading the conditions
1217 * we have to handle AS4_AGGREGATOR as if it were
1218 * AGGREGATOR in that case
1219 */
1220 if ( BGP_DEBUG(as4, AS4))
1221 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1222 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1223 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001224 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001225 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1226 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1227 }
1228 }
1229
1230 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001231 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001232 {
1233 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001234 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001235 attr->aspath = aspath_intern (newpath);
1236 }
Paul Jakmab881c702010-11-23 16:35:42 +00001237 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001238}
1239
paul718e3742002-12-13 20:15:29 +00001240/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001241static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001242bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001243 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001244{
Paul Jakmab881c702010-11-23 16:35:42 +00001245 bgp_size_t total
1246 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1247
paul718e3742002-12-13 20:15:29 +00001248 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001249 {
1250 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001251 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001252 }
Paul Jakma0c466382010-12-05 17:17:26 +00001253
1254 attr->community =
1255 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1256
1257 /* XXX: fix community_parse to use stream API and remove this */
1258 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001259
Paul Jakma0c466382010-12-05 17:17:26 +00001260 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001261 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1262 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1263 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001264
paul718e3742002-12-13 20:15:29 +00001265 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1266
Paul Jakmab881c702010-11-23 16:35:42 +00001267 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001268}
1269
1270/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001271static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001272bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1273 struct attr *attr, u_char flag)
1274{
1275 if (length != 4)
1276 {
1277 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1278
Paul Jakmab881c702010-11-23 16:35:42 +00001279 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1280 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1281 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001282 }
1283
Paul Jakmafb982c22007-05-04 20:15:47 +00001284 (bgp_attr_extra_get (attr))->originator_id.s_addr
1285 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001286
1287 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1288
Paul Jakmab881c702010-11-23 16:35:42 +00001289 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001290}
1291
1292/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001293static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001294bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1295 struct attr *attr, u_char flag)
1296{
1297 /* Check length. */
1298 if (length % 4)
1299 {
1300 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1301
Paul Jakmab881c702010-11-23 16:35:42 +00001302 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1303 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1304 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001305 }
1306
Paul Jakmafb982c22007-05-04 20:15:47 +00001307 (bgp_attr_extra_get (attr))->cluster
1308 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001309
1310 /* XXX: Fix cluster_parse to use stream API and then remove this */
1311 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001312
1313 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1314
Paul Jakmab881c702010-11-23 16:35:42 +00001315 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001316}
1317
1318/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001319int
paul718e3742002-12-13 20:15:29 +00001320bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1321 struct bgp_nlri *mp_update)
1322{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001323 afi_t afi;
1324 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001325 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001326 size_t start;
paul718e3742002-12-13 20:15:29 +00001327 int ret;
1328 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001329 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001330
1331 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001332 s = BGP_INPUT(peer);
1333 start = stream_get_getp(s);
1334
1335 /* safe to read statically sized header? */
1336#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001337#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001338 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001339 {
1340 zlog_info ("%s: %s sent invalid length, %lu",
1341 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001342 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001343 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001344
paul718e3742002-12-13 20:15:29 +00001345 /* Load AFI, SAFI. */
1346 afi = stream_getw (s);
1347 safi = stream_getc (s);
1348
1349 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001350 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001351
Paul Jakma03292802008-06-07 20:37:10 +00001352 if (LEN_LEFT < attre->mp_nexthop_len)
1353 {
1354 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1355 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001356 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001357 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001358
paul718e3742002-12-13 20:15:29 +00001359 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001360 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001361 {
1362 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001363 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001364 /* Probably needed for RFC 2283 */
1365 if (attr->nexthop.s_addr == 0)
1366 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001367 break;
1368 case 12:
1369 {
1370 u_int32_t rd_high;
1371 u_int32_t rd_low;
1372
1373 rd_high = stream_getl (s);
1374 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001375 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001376 }
1377 break;
1378#ifdef HAVE_IPV6
1379 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001380 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001381 break;
1382 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001383 stream_get (&attre->mp_nexthop_global, s, 16);
1384 stream_get (&attre->mp_nexthop_local, s, 16);
1385 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001386 {
1387 char buf1[INET6_ADDRSTRLEN];
1388 char buf2[INET6_ADDRSTRLEN];
1389
1390 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001391 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 +00001392 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001393 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001394 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001395 buf2, INET6_ADDRSTRLEN));
1396
Paul Jakmafb982c22007-05-04 20:15:47 +00001397 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001398 }
1399 break;
1400#endif /* HAVE_IPV6 */
1401 default:
Paul Jakma03292802008-06-07 20:37:10 +00001402 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1403 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001404 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001405 }
1406
Paul Jakma03292802008-06-07 20:37:10 +00001407 if (!LEN_LEFT)
1408 {
1409 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1410 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001411 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001412 }
paul718e3742002-12-13 20:15:29 +00001413
Paul Jakma6e4ab122007-04-10 19:36:48 +00001414 {
1415 u_char val;
1416 if ((val = stream_getc (s)))
1417 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1418 peer->host, val);
1419 }
1420
1421 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001422 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001423 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001424 {
1425 zlog_info ("%s: (%s) Failed to read NLRI",
1426 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001427 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001428 }
paul718e3742002-12-13 20:15:29 +00001429
1430 if (safi != BGP_SAFI_VPNV4)
1431 {
1432 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001433 if (ret < 0)
1434 {
1435 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1436 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001437 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001438 }
paul718e3742002-12-13 20:15:29 +00001439 }
1440
1441 mp_update->afi = afi;
1442 mp_update->safi = safi;
1443 mp_update->nlri = stream_pnt (s);
1444 mp_update->length = nlri_len;
1445
paul9985f832005-02-09 15:51:56 +00001446 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001447
Paul Jakmab881c702010-11-23 16:35:42 +00001448 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001449#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001450}
1451
1452/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001453int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001454bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001455 struct bgp_nlri *mp_withdraw)
1456{
1457 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001458 afi_t afi;
1459 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001460 u_int16_t withdraw_len;
1461 int ret;
1462
1463 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001464
1465#define BGP_MP_UNREACH_MIN_SIZE 3
1466 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001467 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001468
paul718e3742002-12-13 20:15:29 +00001469 afi = stream_getw (s);
1470 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001471
1472 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001473
1474 if (safi != BGP_SAFI_VPNV4)
1475 {
1476 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1477 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001478 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001479 }
1480
1481 mp_withdraw->afi = afi;
1482 mp_withdraw->safi = safi;
1483 mp_withdraw->nlri = stream_pnt (s);
1484 mp_withdraw->length = withdraw_len;
1485
paul9985f832005-02-09 15:51:56 +00001486 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001487
Paul Jakmab881c702010-11-23 16:35:42 +00001488 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001489}
1490
1491/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001492static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001493bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001494 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001495{
Paul Jakmab881c702010-11-23 16:35:42 +00001496 bgp_size_t total
1497 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1498
paul718e3742002-12-13 20:15:29 +00001499 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001500 {
1501 if (attr->extra)
1502 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001503 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001504 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001505 }
Paul Jakma0c466382010-12-05 17:17:26 +00001506
1507 (bgp_attr_extra_get (attr))->ecommunity =
1508 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1509 /* XXX: fix ecommunity_parse to use stream API */
1510 stream_forward_getp (peer->ibuf, length);
1511
1512 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001513 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1514 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1515 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001516
paul718e3742002-12-13 20:15:29 +00001517 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1518
Paul Jakmab881c702010-11-23 16:35:42 +00001519 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001520}
1521
1522/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001523static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001524bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1525 u_char type, bgp_size_t length, u_char *startp)
1526{
1527 bgp_size_t total;
1528 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001529 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001530
hassof4184462005-02-01 20:13:16 +00001531 if (BGP_DEBUG (normal, NORMAL))
1532 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1533 peer->host, type, length);
1534
paul718e3742002-12-13 20:15:29 +00001535 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001536 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001537 "Unknown attribute type %d length %d is received", type, length);
1538
1539 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001540 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001541
1542 /* Adjest total length to include type and length. */
1543 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1544
1545 /* If any of the mandatory well-known attributes are not recognized,
1546 then the Error Subcode is set to Unrecognized Well-known
1547 Attribute. The Data field contains the unrecognized attribute
1548 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001549 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001550 {
Paul Jakmab881c702010-11-23 16:35:42 +00001551 return bgp_attr_malformed (peer, type, flag,
1552 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1553 startp, total);
paul718e3742002-12-13 20:15:29 +00001554 }
1555
1556 /* Unrecognized non-transitive optional attributes must be quietly
1557 ignored and not passed along to other BGP peers. */
1558 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001559 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001560
1561 /* If a path with recognized transitive optional attribute is
1562 accepted and passed along to other BGP peers and the Partial bit
1563 in the Attribute Flags octet is set to 1 by some previous AS, it
1564 is not set back to 0 by the current AS. */
1565 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1566
1567 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001568 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001569 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001570
Paul Jakmafb982c22007-05-04 20:15:47 +00001571 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001572
1573 if (transit->val)
1574 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1575 transit->length + total);
1576 else
1577 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1578
1579 memcpy (transit->val + transit->length, startp, total);
1580 transit->length += total;
1581
Paul Jakmab881c702010-11-23 16:35:42 +00001582 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001583}
1584
1585/* Read attribute of update packet. This function is called from
1586 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001587bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001588bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1589 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1590{
1591 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001592 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001593 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001594 bgp_size_t length;
1595 u_char *startp, *endp;
1596 u_char *attr_endp;
1597 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001598 /* we need the as4_path only until we have synthesized the as_path with it */
1599 /* same goes for as4_aggregator */
1600 struct aspath *as4_path = NULL;
1601 as_t as4_aggregator = 0;
1602 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001603
1604 /* Initialize bitmap. */
1605 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1606
1607 /* End pointer of BGP attribute. */
1608 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001609
paul718e3742002-12-13 20:15:29 +00001610 /* Get attributes to the end of attribute length. */
1611 while (BGP_INPUT_PNT (peer) < endp)
1612 {
1613 /* Check remaining length check.*/
1614 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1615 {
gdtc29fdba2004-12-09 14:46:46 +00001616 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001617 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001618 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001619 peer->host,
1620 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001621
1622 bgp_notify_send (peer,
1623 BGP_NOTIFY_UPDATE_ERR,
1624 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001625 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001626 }
1627
1628 /* Fetch attribute flag and type. */
1629 startp = BGP_INPUT_PNT (peer);
1630 flag = stream_getc (BGP_INPUT (peer));
1631 type = stream_getc (BGP_INPUT (peer));
1632
Paul Jakma370b64a2007-12-22 16:49:52 +00001633 /* Check whether Extended-Length applies and is in bounds */
1634 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1635 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1636 {
1637 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001638 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001639 peer->host,
1640 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1641
1642 bgp_notify_send (peer,
1643 BGP_NOTIFY_UPDATE_ERR,
1644 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001645 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001646 }
1647
paul718e3742002-12-13 20:15:29 +00001648 /* Check extended attribue length bit. */
1649 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1650 length = stream_getw (BGP_INPUT (peer));
1651 else
1652 length = stream_getc (BGP_INPUT (peer));
1653
1654 /* If any attribute appears more than once in the UPDATE
1655 message, then the Error Subcode is set to Malformed Attribute
1656 List. */
1657
1658 if (CHECK_BITMAP (seen, type))
1659 {
1660 zlog (peer->log, LOG_WARNING,
1661 "%s error BGP attribute type %d appears twice in a message",
1662 peer->host, type);
1663
1664 bgp_notify_send (peer,
1665 BGP_NOTIFY_UPDATE_ERR,
1666 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001667 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001668 }
1669
1670 /* Set type to bitmap to check duplicate attribute. `type' is
1671 unsigned char so it never overflow bitmap range. */
1672
1673 SET_BITMAP (seen, type);
1674
1675 /* Overflow check. */
1676 attr_endp = BGP_INPUT_PNT (peer) + length;
1677
1678 if (attr_endp > endp)
1679 {
1680 zlog (peer->log, LOG_WARNING,
1681 "%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);
1682 bgp_notify_send (peer,
1683 BGP_NOTIFY_UPDATE_ERR,
1684 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001685 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001686 }
1687
1688 /* OK check attribute and store it's value. */
1689 switch (type)
1690 {
1691 case BGP_ATTR_ORIGIN:
1692 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1693 break;
1694 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001695 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001696 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001697 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001698 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001699 break;
paul718e3742002-12-13 20:15:29 +00001700 case BGP_ATTR_NEXT_HOP:
1701 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1702 break;
1703 case BGP_ATTR_MULTI_EXIT_DISC:
1704 ret = bgp_attr_med (peer, length, attr, flag, startp);
1705 break;
1706 case BGP_ATTR_LOCAL_PREF:
1707 ret = bgp_attr_local_pref (peer, length, attr, flag);
1708 break;
1709 case BGP_ATTR_ATOMIC_AGGREGATE:
1710 ret = bgp_attr_atomic (peer, length, attr, flag);
1711 break;
1712 case BGP_ATTR_AGGREGATOR:
1713 ret = bgp_attr_aggregator (peer, length, attr, flag);
1714 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001715 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001716 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1717 &as4_aggregator,
1718 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001719 break;
paul718e3742002-12-13 20:15:29 +00001720 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001721 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001722 break;
1723 case BGP_ATTR_ORIGINATOR_ID:
1724 ret = bgp_attr_originator_id (peer, length, attr, flag);
1725 break;
1726 case BGP_ATTR_CLUSTER_LIST:
1727 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1728 break;
1729 case BGP_ATTR_MP_REACH_NLRI:
1730 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1731 break;
1732 case BGP_ATTR_MP_UNREACH_NLRI:
1733 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1734 break;
1735 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001736 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001737 break;
1738 default:
1739 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1740 break;
1741 }
Paul Jakmab881c702010-11-23 16:35:42 +00001742
1743 /* If hard error occured immediately return to the caller. */
1744 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001745 {
1746 zlog (peer->log, LOG_WARNING,
1747 "%s: Attribute %s, parse error",
1748 peer->host,
1749 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001750 bgp_notify_send (peer,
1751 BGP_NOTIFY_UPDATE_ERR,
1752 BGP_NOTIFY_UPDATE_MAL_ATTR);
1753 if (as4_path)
1754 aspath_unintern (&as4_path);
1755 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001756 }
Paul Jakmab881c702010-11-23 16:35:42 +00001757 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1758 {
1759
1760 zlog (peer->log, LOG_WARNING,
1761 "%s: Attribute %s, parse error - treating as withdrawal",
1762 peer->host,
1763 LOOKUP (attr_str, type));
1764 if (as4_path)
1765 aspath_unintern (&as4_path);
1766 return ret;
1767 }
1768
paul718e3742002-12-13 20:15:29 +00001769 /* Check the fetched length. */
1770 if (BGP_INPUT_PNT (peer) != attr_endp)
1771 {
1772 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001773 "%s: BGP attribute %s, fetch error",
1774 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001775 bgp_notify_send (peer,
1776 BGP_NOTIFY_UPDATE_ERR,
1777 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001778 if (as4_path)
1779 aspath_unintern (&as4_path);
1780 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001781 }
1782 }
1783
1784 /* Check final read pointer is same as end pointer. */
1785 if (BGP_INPUT_PNT (peer) != endp)
1786 {
1787 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001788 "%s BGP attribute %s, length mismatch",
1789 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001790 bgp_notify_send (peer,
1791 BGP_NOTIFY_UPDATE_ERR,
1792 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001793 if (as4_path)
1794 aspath_unintern (&as4_path);
1795 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001796 }
1797
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001798 /*
1799 * At this place we can see whether we got AS4_PATH and/or
1800 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1801 * We can not do this before we've read all attributes because
1802 * the as4 handling does not say whether AS4_PATH has to be sent
1803 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1804 * in relationship to AGGREGATOR.
1805 * So, to be defensive, we are not relying on any order and read
1806 * all attributes first, including these 32bit ones, and now,
1807 * afterwards, we look what and if something is to be done for as4.
1808 */
Paul Jakmab881c702010-11-23 16:35:42 +00001809 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001810 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001811 {
1812 if (as4_path)
1813 aspath_unintern (&as4_path);
1814 return BGP_ATTR_PARSE_ERROR;
1815 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001816
1817 /* At this stage, we have done all fiddling with as4, and the
1818 * resulting info is in attr->aggregator resp. attr->aspath
1819 * so we can chuck as4_aggregator and as4_path alltogether in
1820 * order to save memory
1821 */
Paul Jakmab881c702010-11-23 16:35:42 +00001822 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001823 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001824 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001825 /* The flag that we got this is still there, but that does not
1826 * do any trouble
1827 */
1828 }
1829 /*
1830 * The "rest" of the code does nothing with as4_aggregator.
1831 * there is no memory attached specifically which is not part
1832 * of the attr.
1833 * so ignoring just means do nothing.
1834 */
1835 /*
1836 * Finally do the checks on the aspath we did not do yet
1837 * because we waited for a potentially synthesized aspath.
1838 */
Paul Jakmab881c702010-11-23 16:35:42 +00001839 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001840 {
Paul Jakmab881c702010-11-23 16:35:42 +00001841 ret = bgp_attr_aspath_check (peer, attr, flag);
1842 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001843 return ret;
1844 }
1845
paul718e3742002-12-13 20:15:29 +00001846 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001847 if (attr->extra && attr->extra->transit)
1848 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001849
Paul Jakmab881c702010-11-23 16:35:42 +00001850 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001851}
1852
1853/* Well-known attribute check. */
1854int
1855bgp_attr_check (struct peer *peer, struct attr *attr)
1856{
1857 u_char type = 0;
1858
1859 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1860 type = BGP_ATTR_ORIGIN;
1861
1862 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1863 type = BGP_ATTR_AS_PATH;
1864
1865 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1866 type = BGP_ATTR_NEXT_HOP;
1867
1868 if (peer_sort (peer) == BGP_PEER_IBGP
1869 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1870 type = BGP_ATTR_LOCAL_PREF;
1871
1872 if (type)
1873 {
1874 zlog (peer->log, LOG_WARNING,
1875 "%s Missing well-known attribute %d.",
1876 peer->host, type);
1877 bgp_notify_send_with_data (peer,
1878 BGP_NOTIFY_UPDATE_ERR,
1879 BGP_NOTIFY_UPDATE_MISS_ATTR,
1880 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00001881 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001882 }
Paul Jakmab881c702010-11-23 16:35:42 +00001883 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001884}
1885
1886int stream_put_prefix (struct stream *, struct prefix *);
1887
1888/* Make attribute packet. */
1889bgp_size_t
1890bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1891 struct stream *s, struct attr *attr, struct prefix *p,
1892 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001893 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001894{
paulfe69a502005-09-10 16:55:02 +00001895 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001896 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001897 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001898 int send_as4_path = 0;
1899 int send_as4_aggregator = 0;
1900 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001901
1902 if (! bgp)
1903 bgp = bgp_get_default ();
1904
1905 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001906 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001907
1908 /* Origin attribute. */
1909 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1910 stream_putc (s, BGP_ATTR_ORIGIN);
1911 stream_putc (s, 1);
1912 stream_putc (s, attr->origin);
1913
1914 /* AS path attribute. */
1915
1916 /* If remote-peer is EBGP */
1917 if (peer_sort (peer) == BGP_PEER_EBGP
1918 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001919 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001920 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001921 {
1922 aspath = aspath_dup (attr->aspath);
1923
1924 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1925 {
1926 /* Strip the confed info, and then stuff our path CONFED_ID
1927 on the front */
1928 aspath = aspath_delete_confed_seq (aspath);
1929 aspath = aspath_add_seq (aspath, bgp->confed_id);
1930 }
1931 else
1932 {
1933 aspath = aspath_add_seq (aspath, peer->local_as);
1934 if (peer->change_local_as)
1935 aspath = aspath_add_seq (aspath, peer->change_local_as);
1936 }
1937 }
1938 else if (peer_sort (peer) == BGP_PEER_CONFED)
1939 {
1940 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1941 aspath = aspath_dup (attr->aspath);
1942 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1943 }
1944 else
1945 aspath = attr->aspath;
1946
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001947 /* If peer is not AS4 capable, then:
1948 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1949 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1950 * types are in it (i.e. exclude them if they are there)
1951 * AND do this only if there is at least one asnum > 65535 in the path!
1952 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1953 * all ASnums > 65535 to BGP_AS_TRANS
1954 */
paul718e3742002-12-13 20:15:29 +00001955
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001956 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1957 stream_putc (s, BGP_ATTR_AS_PATH);
1958 aspath_sizep = stream_get_endp (s);
1959 stream_putw (s, 0);
1960 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1961
1962 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1963 * in the path
1964 */
1965 if (!use32bit && aspath_has_as4 (aspath))
1966 send_as4_path = 1; /* we'll do this later, at the correct place */
1967
paul718e3742002-12-13 20:15:29 +00001968 /* Nexthop attribute. */
1969 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1970 {
1971 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1972 stream_putc (s, BGP_ATTR_NEXT_HOP);
1973 stream_putc (s, 4);
1974 if (safi == SAFI_MPLS_VPN)
1975 {
1976 if (attr->nexthop.s_addr == 0)
1977 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1978 else
1979 stream_put_ipv4 (s, attr->nexthop.s_addr);
1980 }
1981 else
1982 stream_put_ipv4 (s, attr->nexthop.s_addr);
1983 }
1984
1985 /* MED attribute. */
1986 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1987 {
1988 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1989 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1990 stream_putc (s, 4);
1991 stream_putl (s, attr->med);
1992 }
1993
1994 /* Local preference. */
1995 if (peer_sort (peer) == BGP_PEER_IBGP ||
1996 peer_sort (peer) == BGP_PEER_CONFED)
1997 {
1998 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1999 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2000 stream_putc (s, 4);
2001 stream_putl (s, attr->local_pref);
2002 }
2003
2004 /* Atomic aggregate. */
2005 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2006 {
2007 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2008 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2009 stream_putc (s, 0);
2010 }
2011
2012 /* Aggregator. */
2013 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2014 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002015 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002016
2017 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002018 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2019 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002020
2021 if (use32bit)
2022 {
2023 /* AS4 capable peer */
2024 stream_putc (s, 8);
2025 stream_putl (s, attr->extra->aggregator_as);
2026 }
2027 else
2028 {
2029 /* 2-byte AS peer */
2030 stream_putc (s, 6);
2031
2032 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2033 if ( attr->extra->aggregator_as > 65535 )
2034 {
2035 stream_putw (s, BGP_AS_TRANS);
2036
2037 /* we have to send AS4_AGGREGATOR, too.
2038 * we'll do that later in order to send attributes in ascending
2039 * order.
2040 */
2041 send_as4_aggregator = 1;
2042 }
2043 else
2044 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2045 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002046 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002047 }
2048
2049 /* Community attribute. */
2050 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2051 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2052 {
2053 if (attr->community->size * 4 > 255)
2054 {
2055 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2056 stream_putc (s, BGP_ATTR_COMMUNITIES);
2057 stream_putw (s, attr->community->size * 4);
2058 }
2059 else
2060 {
2061 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2062 stream_putc (s, BGP_ATTR_COMMUNITIES);
2063 stream_putc (s, attr->community->size * 4);
2064 }
2065 stream_put (s, attr->community->val, attr->community->size * 4);
2066 }
2067
2068 /* Route Reflector. */
2069 if (peer_sort (peer) == BGP_PEER_IBGP
2070 && from
2071 && peer_sort (from) == BGP_PEER_IBGP)
2072 {
2073 /* Originator ID. */
2074 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2075 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2076 stream_putc (s, 4);
2077
2078 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002079 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002080 else
2081 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002082
2083 /* Cluster list. */
2084 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2085 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2086
Paul Jakma9eda90c2007-08-30 13:36:17 +00002087 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002088 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002089 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002090 /* If this peer configuration's parent BGP has cluster_id. */
2091 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2092 stream_put_in_addr (s, &bgp->cluster_id);
2093 else
2094 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002095 stream_put (s, attr->extra->cluster->list,
2096 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002097 }
2098 else
2099 {
2100 stream_putc (s, 4);
2101 /* If this peer configuration's parent BGP has cluster_id. */
2102 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2103 stream_put_in_addr (s, &bgp->cluster_id);
2104 else
2105 stream_put_in_addr (s, &bgp->router_id);
2106 }
2107 }
2108
2109#ifdef HAVE_IPV6
2110 /* If p is IPv6 address put it into attribute. */
2111 if (p->family == AF_INET6)
2112 {
2113 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002114 struct attr_extra *attre = attr->extra;
2115
2116 assert (attr->extra);
2117
paul718e3742002-12-13 20:15:29 +00002118 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2119 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002120 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002121 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002122 stream_putw (s, AFI_IP6); /* AFI */
2123 stream_putc (s, safi); /* SAFI */
2124
Paul Jakmafb982c22007-05-04 20:15:47 +00002125 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002126
Paul Jakmafb982c22007-05-04 20:15:47 +00002127 if (attre->mp_nexthop_len == 16)
2128 stream_put (s, &attre->mp_nexthop_global, 16);
2129 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002130 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002131 stream_put (s, &attre->mp_nexthop_global, 16);
2132 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002133 }
2134
2135 /* SNPA */
2136 stream_putc (s, 0);
2137
paul718e3742002-12-13 20:15:29 +00002138 /* Prefix write. */
2139 stream_put_prefix (s, p);
2140
2141 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002142 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002143 }
2144#endif /* HAVE_IPV6 */
2145
2146 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2147 {
2148 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002149
2150 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2151 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002152 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002153 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002154 stream_putw (s, AFI_IP); /* AFI */
2155 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2156
2157 stream_putc (s, 4);
2158 stream_put_ipv4 (s, attr->nexthop.s_addr);
2159
2160 /* SNPA */
2161 stream_putc (s, 0);
2162
paul718e3742002-12-13 20:15:29 +00002163 /* Prefix write. */
2164 stream_put_prefix (s, p);
2165
2166 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002167 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002168 }
2169
2170 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2171 {
2172 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002173
2174 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2175 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002176 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002177 stream_putc (s, 0); /* Length of this attribute. */
2178 stream_putw (s, AFI_IP); /* AFI */
2179 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2180
2181 stream_putc (s, 12);
2182 stream_putl (s, 0);
2183 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002184 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002185
2186 /* SNPA */
2187 stream_putc (s, 0);
2188
paul718e3742002-12-13 20:15:29 +00002189 /* Tag, RD, Prefix write. */
2190 stream_putc (s, p->prefixlen + 88);
2191 stream_put (s, tag, 3);
2192 stream_put (s, prd->val, 8);
2193 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2194
2195 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002196 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002197 }
2198
2199 /* Extended Communities attribute. */
2200 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2201 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2202 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002203 struct attr_extra *attre = attr->extra;
2204
2205 assert (attre);
2206
2207 if (peer_sort (peer) == BGP_PEER_IBGP
2208 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002209 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002210 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002211 {
2212 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2213 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002214 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002215 }
2216 else
2217 {
2218 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2219 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002220 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002221 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002222 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002223 }
2224 else
2225 {
paul5228ad22004-06-04 17:58:18 +00002226 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002227 int tbit;
2228 int ecom_tr_size = 0;
2229 int i;
2230
Paul Jakmafb982c22007-05-04 20:15:47 +00002231 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002232 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002233 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002234 tbit = *pnt;
2235
2236 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2237 continue;
2238
2239 ecom_tr_size++;
2240 }
2241
2242 if (ecom_tr_size)
2243 {
2244 if (ecom_tr_size * 8 > 255)
2245 {
2246 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2247 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2248 stream_putw (s, ecom_tr_size * 8);
2249 }
2250 else
2251 {
2252 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2253 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2254 stream_putc (s, ecom_tr_size * 8);
2255 }
2256
Paul Jakmafb982c22007-05-04 20:15:47 +00002257 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002258 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002259 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002260 tbit = *pnt;
2261
2262 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2263 continue;
2264
2265 stream_put (s, pnt, 8);
2266 }
2267 }
paul718e3742002-12-13 20:15:29 +00002268 }
paul718e3742002-12-13 20:15:29 +00002269 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002270
2271 if ( send_as4_path )
2272 {
2273 /* If the peer is NOT As4 capable, AND */
2274 /* there are ASnums > 65535 in path THEN
2275 * give out AS4_PATH */
2276
2277 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2278 * path segments!
2279 * Hm, I wonder... confederation things *should* only be at
2280 * the beginning of an aspath, right? Then we should use
2281 * aspath_delete_confed_seq for this, because it is already
2282 * there! (JK)
2283 * Folks, talk to me: what is reasonable here!?
2284 */
2285 aspath = aspath_delete_confed_seq (aspath);
2286
2287 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2288 stream_putc (s, BGP_ATTR_AS4_PATH);
2289 aspath_sizep = stream_get_endp (s);
2290 stream_putw (s, 0);
2291 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2292 }
2293
2294 if (aspath != attr->aspath)
2295 aspath_free (aspath);
2296
2297 if ( send_as4_aggregator )
2298 {
2299 assert (attr->extra);
2300
2301 /* send AS4_AGGREGATOR, at this place */
2302 /* this section of code moved here in order to ensure the correct
2303 * *ascending* order of attributes
2304 */
2305 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2306 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2307 stream_putc (s, 8);
2308 stream_putl (s, attr->extra->aggregator_as);
2309 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2310 }
Paul Jakma41367172007-08-06 15:24:51 +00002311
paul718e3742002-12-13 20:15:29 +00002312 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002313 if (attr->extra && attr->extra->transit)
2314 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002315
2316 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002317 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002318}
2319
2320bgp_size_t
2321bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2322 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002323 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002324{
2325 unsigned long cp;
2326 unsigned long attrlen_pnt;
2327 bgp_size_t size;
2328
paul9985f832005-02-09 15:51:56 +00002329 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002330
2331 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2332 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2333
paul9985f832005-02-09 15:51:56 +00002334 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002335 stream_putc (s, 0); /* Length of this attribute. */
2336
2337 stream_putw (s, family2afi (p->family));
2338
2339 if (safi == SAFI_MPLS_VPN)
2340 {
2341 /* SAFI */
2342 stream_putc (s, BGP_SAFI_VPNV4);
2343
2344 /* prefix. */
2345 stream_putc (s, p->prefixlen + 88);
2346 stream_put (s, tag, 3);
2347 stream_put (s, prd->val, 8);
2348 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2349 }
2350 else
2351 {
2352 /* SAFI */
2353 stream_putc (s, safi);
2354
2355 /* prefix */
2356 stream_put_prefix (s, p);
2357 }
2358
2359 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002360 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002361 stream_putc_at (s, attrlen_pnt, size);
2362
paul9985f832005-02-09 15:51:56 +00002363 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002364}
2365
2366/* Initialization of attribute. */
2367void
paulfe69a502005-09-10 16:55:02 +00002368bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002369{
paul718e3742002-12-13 20:15:29 +00002370 aspath_init ();
2371 attrhash_init ();
2372 community_init ();
2373 ecommunity_init ();
2374 cluster_init ();
2375 transit_init ();
2376}
2377
Chris Caputo228da422009-07-18 05:44:03 +00002378void
2379bgp_attr_finish (void)
2380{
2381 aspath_finish ();
2382 attrhash_finish ();
2383 community_finish ();
2384 ecommunity_finish ();
2385 cluster_finish ();
2386 transit_finish ();
2387}
2388
paul718e3742002-12-13 20:15:29 +00002389/* Make attribute packet. */
2390void
paula3845922003-10-18 01:30:50 +00002391bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2392 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002393{
2394 unsigned long cp;
2395 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002396 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002397 struct aspath *aspath;
2398
2399 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002400 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002401
2402 /* Place holder of length. */
2403 stream_putw (s, 0);
2404
2405 /* Origin attribute. */
2406 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2407 stream_putc (s, BGP_ATTR_ORIGIN);
2408 stream_putc (s, 1);
2409 stream_putc (s, attr->origin);
2410
2411 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002412
2413 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2414 stream_putc (s, BGP_ATTR_AS_PATH);
2415 aspath_lenp = stream_get_endp (s);
2416 stream_putw (s, 0);
2417
2418 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002419
2420 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002421 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2422 if(prefix != NULL
2423#ifdef HAVE_IPV6
2424 && prefix->family != AF_INET6
2425#endif /* HAVE_IPV6 */
2426 )
2427 {
2428 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2429 stream_putc (s, BGP_ATTR_NEXT_HOP);
2430 stream_putc (s, 4);
2431 stream_put_ipv4 (s, attr->nexthop.s_addr);
2432 }
paul718e3742002-12-13 20:15:29 +00002433
2434 /* MED attribute. */
2435 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2436 {
2437 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2438 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2439 stream_putc (s, 4);
2440 stream_putl (s, attr->med);
2441 }
2442
2443 /* Local preference. */
2444 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2445 {
2446 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2447 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2448 stream_putc (s, 4);
2449 stream_putl (s, attr->local_pref);
2450 }
2451
2452 /* Atomic aggregate. */
2453 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2454 {
2455 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2456 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2457 stream_putc (s, 0);
2458 }
2459
2460 /* Aggregator. */
2461 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2462 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002463 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002464 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2465 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002466 stream_putc (s, 8);
2467 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002468 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002469 }
2470
2471 /* Community attribute. */
2472 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2473 {
2474 if (attr->community->size * 4 > 255)
2475 {
2476 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2477 stream_putc (s, BGP_ATTR_COMMUNITIES);
2478 stream_putw (s, attr->community->size * 4);
2479 }
2480 else
2481 {
2482 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2483 stream_putc (s, BGP_ATTR_COMMUNITIES);
2484 stream_putc (s, attr->community->size * 4);
2485 }
2486 stream_put (s, attr->community->val, attr->community->size * 4);
2487 }
2488
paula3845922003-10-18 01:30:50 +00002489#ifdef HAVE_IPV6
2490 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002491 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2492 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002493 {
2494 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002495 struct attr_extra *attre = attr->extra;
2496
paula3845922003-10-18 01:30:50 +00002497 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2498 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002499 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002500
2501 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002502 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002503 stream_putw(s, AFI_IP6); /* AFI */
2504 stream_putc(s, SAFI_UNICAST); /* SAFI */
2505
2506 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002507 stream_putc(s, attre->mp_nexthop_len);
2508 stream_put(s, &attre->mp_nexthop_global, 16);
2509 if (attre->mp_nexthop_len == 32)
2510 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002511
2512 /* SNPA */
2513 stream_putc(s, 0);
2514
2515 /* Prefix */
2516 stream_put_prefix(s, prefix);
2517
2518 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002519 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002520 }
2521#endif /* HAVE_IPV6 */
2522
paul718e3742002-12-13 20:15:29 +00002523 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002524 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002525 stream_putw_at (s, cp, len);
2526}