blob: 0c5355b4e5ad178e8da793e9d6ced477d823513d [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);
376 key = jhash2(attr->extra->mp_nexthop_global.s6_addr32, 4, key);
377 key = jhash2(attr->extra->mp_nexthop_local.s6_addr32, 4, 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
621/* Free bgp attribute and aspath. */
622void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000623bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000624{
625 struct attr *ret;
626 struct aspath *aspath;
627 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000628 struct ecommunity *ecommunity = NULL;
629 struct cluster_list *cluster = NULL;
630 struct transit *transit = NULL;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000631
paul718e3742002-12-13 20:15:29 +0000632 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000633 (*attr)->refcnt--;
634 aspath = (*attr)->aspath;
635 community = (*attr)->community;
636 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000637 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000638 ecommunity = (*attr)->extra->ecommunity;
639 cluster = (*attr)->extra->cluster;
640 transit = (*attr)->extra->transit;
Paul Jakmafb982c22007-05-04 20:15:47 +0000641 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000642
paul718e3742002-12-13 20:15:29 +0000643 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000644 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000645 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000646 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000647 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000648 bgp_attr_extra_free (*attr);
649 XFREE (MTYPE_ATTR, *attr);
650 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000651 }
652
653 /* aspath refcount shoud be decrement. */
654 if (aspath)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000655 aspath_unintern (&aspath);
paul718e3742002-12-13 20:15:29 +0000656 if (community)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000657 community_unintern (&community);
paul718e3742002-12-13 20:15:29 +0000658 if (ecommunity)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000659 ecommunity_unintern (&ecommunity);
paul718e3742002-12-13 20:15:29 +0000660 if (cluster)
661 cluster_unintern (cluster);
662 if (transit)
663 transit_unintern (transit);
664}
665
666void
667bgp_attr_flush (struct attr *attr)
668{
669 if (attr->aspath && ! attr->aspath->refcnt)
670 aspath_free (attr->aspath);
671 if (attr->community && ! attr->community->refcnt)
672 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000673 if (attr->extra)
674 {
675 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000676
Paul Jakmafb982c22007-05-04 20:15:47 +0000677 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000678 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000679 if (attre->cluster && ! attre->cluster->refcnt)
680 cluster_free (attre->cluster);
681 if (attre->transit && ! attre->transit->refcnt)
682 transit_free (attre->transit);
683 }
paul718e3742002-12-13 20:15:29 +0000684}
685
686/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000687static int
paul718e3742002-12-13 20:15:29 +0000688bgp_attr_origin (struct peer *peer, bgp_size_t length,
689 struct attr *attr, u_char flag, u_char *startp)
690{
691 bgp_size_t total;
692
693 /* total is entire attribute length include Attribute Flags (1),
694 Attribute Type code (1) and Attribute length (1 or 2). */
695 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
696
697 /* If any recognized attribute has Attribute Flags that conflict
698 with the Attribute Type Code, then the Error Subcode is set to
699 Attribute Flags Error. The Data field contains the erroneous
700 attribute (type, length and value). */
701 if (flag != BGP_ATTR_FLAG_TRANS)
702 {
703 zlog (peer->log, LOG_ERR,
704 "Origin attribute flag isn't transitive %d", flag);
705 bgp_notify_send_with_data (peer,
706 BGP_NOTIFY_UPDATE_ERR,
707 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
708 startp, total);
709 return -1;
710 }
711
712 /* If any recognized attribute has Attribute Length that conflicts
713 with the expected length (based on the attribute type code), then
714 the Error Subcode is set to Attribute Length Error. The Data
715 field contains the erroneous attribute (type, length and
716 value). */
717 if (length != 1)
718 {
719 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
720 length);
721 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
722 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
723 startp, total);
724 return -1;
725 }
726
727 /* Fetch origin attribute. */
728 attr->origin = stream_getc (BGP_INPUT (peer));
729
730 /* If the ORIGIN attribute has an undefined value, then the Error
731 Subcode is set to Invalid Origin Attribute. The Data field
732 contains the unrecognized attribute (type, length and value). */
733 if ((attr->origin != BGP_ORIGIN_IGP)
734 && (attr->origin != BGP_ORIGIN_EGP)
735 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
736 {
737 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
738 attr->origin);
739
740 bgp_notify_send_with_data (peer,
741 BGP_NOTIFY_UPDATE_ERR,
742 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
743 startp, total);
744 return -1;
745 }
746
747 /* Set oring attribute flag. */
748 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
749
750 return 0;
751}
Paul Jakmaab005292010-11-27 22:48:34 +0000752
753/* Parse AS path information. This function is wrapper of
754 aspath_parse. */
755static int
paul718e3742002-12-13 20:15:29 +0000756bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000757 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000758{
Paul Jakmaab005292010-11-27 22:48:34 +0000759 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000760
Paul Jakmaab005292010-11-27 22:48:34 +0000761 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000762
Paul Jakmaab005292010-11-27 22:48:34 +0000763 /* Flag check. */
764 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
765 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000766 {
767 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000768 "As-Path attribute flag isn't transitive %d", flag);
paul718e3742002-12-13 20:15:29 +0000769 bgp_notify_send_with_data (peer,
770 BGP_NOTIFY_UPDATE_ERR,
771 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
772 startp, total);
Paul Jakmaab005292010-11-27 22:48:34 +0000773 return -1;
Chris Hallcddb8112010-08-09 22:31:37 +0400774 }
Paul Jakmaab005292010-11-27 22:48:34 +0000775
776 /*
777 * peer with AS4 => will get 4Byte ASnums
778 * otherwise, will get 16 Bit
779 */
780 attr->aspath = aspath_parse (peer->ibuf, length,
781 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
782
783 /* In case of IBGP, length will be zero. */
784 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000785 {
786 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
787 bgp_notify_send (peer,
788 BGP_NOTIFY_UPDATE_ERR,
789 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Paul Jakmaab005292010-11-27 22:48:34 +0000790 return -1;
791 }
paul718e3742002-12-13 20:15:29 +0000792
Paul Jakmaab005292010-11-27 22:48:34 +0000793 /* Set aspath attribute flag. */
794 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
795
796 return 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000797}
798
799static int bgp_attr_aspath_check( struct peer *peer,
800 struct attr *attr)
801{
802 /* These checks were part of bgp_attr_aspath, but with
803 * as4 we should to check aspath things when
804 * aspath synthesizing with as4_path has already taken place.
805 * Otherwise we check ASPATH and use the synthesized thing, and that is
806 * not right.
807 * So do the checks later, i.e. here
808 */
809 struct bgp *bgp = peer->bgp;
810 struct aspath *aspath;
811
paul718e3742002-12-13 20:15:29 +0000812 bgp = peer->bgp;
813
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300814 /* Confederation sanity check. */
815 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
816 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
817 {
818 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
819 bgp_notify_send (peer,
820 BGP_NOTIFY_UPDATE_ERR,
821 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
822 return -1;
823 }
824
paul718e3742002-12-13 20:15:29 +0000825 /* First AS check for EBGP. */
826 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
827 {
828 if (peer_sort (peer) == BGP_PEER_EBGP
829 && ! aspath_firstas_check (attr->aspath, peer->as))
830 {
831 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400832 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000833 bgp_notify_send (peer,
834 BGP_NOTIFY_UPDATE_ERR,
835 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
836 return -1;
837 }
838 }
839
840 /* local-as prepend */
841 if (peer->change_local_as &&
842 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
843 {
844 aspath = aspath_dup (attr->aspath);
845 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000846 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000847 attr->aspath = aspath_intern (aspath);
848 }
849
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000850 return 0;
851
852}
853
Paul Jakmaab005292010-11-27 22:48:34 +0000854/* Parse AS4 path information. This function is another wrapper of
855 aspath_parse. */
856static int
857bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
858 struct attr *attr, struct aspath **as4_path)
859{
860 *as4_path = aspath_parse (peer->ibuf, length, 1);
861
862 /* Set aspath attribute flag. */
863 if (as4_path)
864 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
865
866 return 0;
867}
868
paul718e3742002-12-13 20:15:29 +0000869/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000870static int
paul718e3742002-12-13 20:15:29 +0000871bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
872 struct attr *attr, u_char flag, u_char *startp)
873{
874 bgp_size_t total;
875
876 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
877
878 /* Flag check. */
879 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
880 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
881 {
882 zlog (peer->log, LOG_ERR,
883 "Origin attribute flag isn't transitive %d", flag);
884 bgp_notify_send_with_data (peer,
885 BGP_NOTIFY_UPDATE_ERR,
886 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
887 startp, total);
888 return -1;
889 }
890
891 /* Check nexthop attribute length. */
892 if (length != 4)
893 {
894 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
895 length);
896
897 bgp_notify_send_with_data (peer,
898 BGP_NOTIFY_UPDATE_ERR,
899 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
900 startp, total);
901 return -1;
902 }
903
904 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
905 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
906
907 return 0;
908}
909
910/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000911static int
paul718e3742002-12-13 20:15:29 +0000912bgp_attr_med (struct peer *peer, bgp_size_t length,
913 struct attr *attr, u_char flag, u_char *startp)
914{
915 bgp_size_t total;
916
917 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
918
919 /* Length check. */
920 if (length != 4)
921 {
922 zlog (peer->log, LOG_ERR,
923 "MED attribute length isn't four [%d]", length);
924
925 bgp_notify_send_with_data (peer,
926 BGP_NOTIFY_UPDATE_ERR,
927 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
928 startp, total);
929 return -1;
930 }
931
932 attr->med = stream_getl (peer->ibuf);
933
934 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
935
936 return 0;
937}
938
939/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000940static int
paul718e3742002-12-13 20:15:29 +0000941bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
942 struct attr *attr, u_char flag)
943{
944 /* If it is contained in an UPDATE message that is received from an
945 external peer, then this attribute MUST be ignored by the
946 receiving speaker. */
947 if (peer_sort (peer) == BGP_PEER_EBGP)
948 {
paul9985f832005-02-09 15:51:56 +0000949 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000950 return 0;
951 }
952
953 if (length == 4)
954 attr->local_pref = stream_getl (peer->ibuf);
955 else
956 attr->local_pref = 0;
957
958 /* Set atomic aggregate flag. */
959 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
960
961 return 0;
962}
963
964/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000965static int
paul718e3742002-12-13 20:15:29 +0000966bgp_attr_atomic (struct peer *peer, bgp_size_t length,
967 struct attr *attr, u_char flag)
968{
969 if (length != 0)
970 {
971 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
972
973 bgp_notify_send (peer,
974 BGP_NOTIFY_UPDATE_ERR,
975 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
976 return -1;
977 }
978
979 /* Set atomic aggregate flag. */
980 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
981
982 return 0;
983}
984
985/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000986static int
paul718e3742002-12-13 20:15:29 +0000987bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
988 struct attr *attr, u_char flag)
989{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000990 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +0000991 struct attr_extra *attre = bgp_attr_extra_get (attr);
992
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000993 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
994 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
995 wantedlen = 8;
996
997 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +0000998 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000999 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001000
1001 bgp_notify_send (peer,
1002 BGP_NOTIFY_UPDATE_ERR,
1003 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1004 return -1;
1005 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001006
1007 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1008 attre->aggregator_as = stream_getl (peer->ibuf);
1009 else
1010 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001011 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001012
1013 /* Set atomic aggregate flag. */
1014 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1015
1016 return 0;
1017}
1018
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001019/* New Aggregator attribute */
1020static int
1021bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1022 struct attr *attr, as_t *as4_aggregator_as,
1023 struct in_addr *as4_aggregator_addr)
1024{
1025 if (length != 8)
1026 {
1027 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1028
1029 bgp_notify_send (peer,
1030 BGP_NOTIFY_UPDATE_ERR,
1031 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1032 return -1;
1033 }
1034 *as4_aggregator_as = stream_getl (peer->ibuf);
1035 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1036
1037 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1038
1039 return 0;
1040}
1041
1042/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1043 */
1044static int
1045bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1046 struct aspath *as4_path, as_t as4_aggregator,
1047 struct in_addr *as4_aggregator_addr)
1048{
1049 int ignore_as4_path = 0;
1050 struct aspath *newpath;
1051 struct attr_extra *attre = attr->extra;
1052
1053 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1054 {
1055 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1056 * if given.
1057 * It is worth a warning though, because the peer really
1058 * should not send them
1059 */
1060 if (BGP_DEBUG(as4, AS4))
1061 {
1062 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1063 zlog_debug ("[AS4] %s %s AS4_PATH",
1064 peer->host, "AS4 capable peer, yet it sent");
1065
1066 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1067 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1068 peer->host, "AS4 capable peer, yet it sent");
1069 }
1070
1071 return 0;
1072 }
1073
1074 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1075 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1076 {
1077 /* Hu? This is not supposed to happen at all!
1078 * got as4_path and no aspath,
1079 * This should already
1080 * have been handled by 'well known attributes missing'
1081 * But... yeah, paranoia
1082 * Take this as a "malformed attribute"
1083 */
1084 zlog (peer->log, LOG_ERR,
1085 "%s BGP not AS4 capable peer sent AS4_PATH but"
1086 " no AS_PATH, cant do anything here", peer->host);
1087 bgp_notify_send (peer,
1088 BGP_NOTIFY_UPDATE_ERR,
1089 BGP_NOTIFY_UPDATE_MAL_ATTR);
1090 return -1;
1091 }
1092
1093 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1094 * because that may override AS4_PATH
1095 */
1096 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1097 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001098 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1099 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001100 assert (attre);
1101
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001102 /* received both.
1103 * if the as_number in aggregator is not AS_TRANS,
1104 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1105 * and the Aggregator shall be taken as
1106 * info on the aggregating node, and the AS_PATH
1107 * shall be taken as the AS_PATH
1108 * otherwise
1109 * the Aggregator shall be ignored and the
1110 * AS4_AGGREGATOR shall be taken as the
1111 * Aggregating node and the AS_PATH is to be
1112 * constructed "as in all other cases"
1113 */
1114 if ( attre->aggregator_as != BGP_AS_TRANS )
1115 {
1116 /* ignore */
1117 if ( BGP_DEBUG(as4, AS4))
1118 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1119 " send AGGREGATOR != AS_TRANS and"
1120 " AS4_AGGREGATOR, so ignore"
1121 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1122 ignore_as4_path = 1;
1123 }
1124 else
1125 {
1126 /* "New_aggregator shall be taken as aggregator" */
1127 attre->aggregator_as = as4_aggregator;
1128 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1129 }
1130 }
1131 else
1132 {
1133 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1134 * That is bogus - but reading the conditions
1135 * we have to handle AS4_AGGREGATOR as if it were
1136 * AGGREGATOR in that case
1137 */
1138 if ( BGP_DEBUG(as4, AS4))
1139 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1140 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1141 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001142 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001143 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1144 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1145 }
1146 }
1147
1148 /* need to reconcile NEW_AS_PATH and AS_PATH */
1149 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1150 {
1151 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001152 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001153 attr->aspath = aspath_intern (newpath);
1154 }
1155 return 0;
1156}
1157
paul718e3742002-12-13 20:15:29 +00001158/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001159static int
paul718e3742002-12-13 20:15:29 +00001160bgp_attr_community (struct peer *peer, bgp_size_t length,
1161 struct attr *attr, u_char flag)
1162{
1163 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001164 {
1165 attr->community = NULL;
1166 return 0;
1167 }
Paul Jakma0c466382010-12-05 17:17:26 +00001168
1169 attr->community =
1170 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1171
1172 /* XXX: fix community_parse to use stream API and remove this */
1173 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001174
Paul Jakma0c466382010-12-05 17:17:26 +00001175 if (!attr->community)
1176 return -1;
1177
paul718e3742002-12-13 20:15:29 +00001178 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1179
1180 return 0;
1181}
1182
1183/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001184static int
paul718e3742002-12-13 20:15:29 +00001185bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1186 struct attr *attr, u_char flag)
1187{
1188 if (length != 4)
1189 {
1190 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1191
1192 bgp_notify_send (peer,
1193 BGP_NOTIFY_UPDATE_ERR,
1194 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1195 return -1;
1196 }
1197
Paul Jakmafb982c22007-05-04 20:15:47 +00001198 (bgp_attr_extra_get (attr))->originator_id.s_addr
1199 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001200
1201 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1202
1203 return 0;
1204}
1205
1206/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001207static int
paul718e3742002-12-13 20:15:29 +00001208bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1209 struct attr *attr, u_char flag)
1210{
1211 /* Check length. */
1212 if (length % 4)
1213 {
1214 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1215
1216 bgp_notify_send (peer,
1217 BGP_NOTIFY_UPDATE_ERR,
1218 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1219 return -1;
1220 }
1221
Paul Jakmafb982c22007-05-04 20:15:47 +00001222 (bgp_attr_extra_get (attr))->cluster
1223 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001224
paul9985f832005-02-09 15:51:56 +00001225 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001226
1227 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1228
1229 return 0;
1230}
1231
1232/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001233int
paul718e3742002-12-13 20:15:29 +00001234bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1235 struct bgp_nlri *mp_update)
1236{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001237 afi_t afi;
1238 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001239 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001240 size_t start;
paul718e3742002-12-13 20:15:29 +00001241 int ret;
1242 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001243 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001244
1245 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001246 s = BGP_INPUT(peer);
1247 start = stream_get_getp(s);
1248
1249 /* safe to read statically sized header? */
1250#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001251#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001252 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001253 {
1254 zlog_info ("%s: %s sent invalid length, %lu",
1255 __func__, peer->host, (unsigned long)length);
1256 return -1;
1257 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001258
paul718e3742002-12-13 20:15:29 +00001259 /* Load AFI, SAFI. */
1260 afi = stream_getw (s);
1261 safi = stream_getc (s);
1262
1263 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001264 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001265
Paul Jakma03292802008-06-07 20:37:10 +00001266 if (LEN_LEFT < attre->mp_nexthop_len)
1267 {
1268 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1269 __func__, peer->host, attre->mp_nexthop_len);
1270 return -1;
1271 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001272
paul718e3742002-12-13 20:15:29 +00001273 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001274 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001275 {
1276 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001277 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001278 /* Probably needed for RFC 2283 */
1279 if (attr->nexthop.s_addr == 0)
1280 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001281 break;
1282 case 12:
1283 {
1284 u_int32_t rd_high;
1285 u_int32_t rd_low;
1286
1287 rd_high = stream_getl (s);
1288 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001289 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001290 }
1291 break;
1292#ifdef HAVE_IPV6
1293 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001294 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001295 break;
1296 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001297 stream_get (&attre->mp_nexthop_global, s, 16);
1298 stream_get (&attre->mp_nexthop_local, s, 16);
1299 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001300 {
1301 char buf1[INET6_ADDRSTRLEN];
1302 char buf2[INET6_ADDRSTRLEN];
1303
1304 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001305 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 +00001306 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001307 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001308 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001309 buf2, INET6_ADDRSTRLEN));
1310
Paul Jakmafb982c22007-05-04 20:15:47 +00001311 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001312 }
1313 break;
1314#endif /* HAVE_IPV6 */
1315 default:
Paul Jakma03292802008-06-07 20:37:10 +00001316 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1317 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001318 return -1;
paul718e3742002-12-13 20:15:29 +00001319 }
1320
Paul Jakma03292802008-06-07 20:37:10 +00001321 if (!LEN_LEFT)
1322 {
1323 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1324 __func__, peer->host);
1325 return -1;
1326 }
paul718e3742002-12-13 20:15:29 +00001327
Paul Jakma6e4ab122007-04-10 19:36:48 +00001328 {
1329 u_char val;
1330 if ((val = stream_getc (s)))
1331 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1332 peer->host, val);
1333 }
1334
1335 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001336 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001337 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001338 {
1339 zlog_info ("%s: (%s) Failed to read NLRI",
1340 __func__, peer->host);
1341 return -1;
1342 }
paul718e3742002-12-13 20:15:29 +00001343
1344 if (safi != BGP_SAFI_VPNV4)
1345 {
1346 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001347 if (ret < 0)
1348 {
1349 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1350 __func__, peer->host);
1351 return -1;
1352 }
paul718e3742002-12-13 20:15:29 +00001353 }
1354
1355 mp_update->afi = afi;
1356 mp_update->safi = safi;
1357 mp_update->nlri = stream_pnt (s);
1358 mp_update->length = nlri_len;
1359
paul9985f832005-02-09 15:51:56 +00001360 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001361
1362 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001363#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001364}
1365
1366/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001367int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001368bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001369 struct bgp_nlri *mp_withdraw)
1370{
1371 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001372 afi_t afi;
1373 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001374 u_int16_t withdraw_len;
1375 int ret;
1376
1377 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001378
1379#define BGP_MP_UNREACH_MIN_SIZE 3
1380 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1381 return -1;
1382
paul718e3742002-12-13 20:15:29 +00001383 afi = stream_getw (s);
1384 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001385
1386 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001387
1388 if (safi != BGP_SAFI_VPNV4)
1389 {
1390 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1391 if (ret < 0)
1392 return -1;
1393 }
1394
1395 mp_withdraw->afi = afi;
1396 mp_withdraw->safi = safi;
1397 mp_withdraw->nlri = stream_pnt (s);
1398 mp_withdraw->length = withdraw_len;
1399
paul9985f832005-02-09 15:51:56 +00001400 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001401
1402 return 0;
1403}
1404
1405/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001406static int
paul718e3742002-12-13 20:15:29 +00001407bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1408 struct attr *attr, u_char flag)
1409{
1410 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001411 {
1412 if (attr->extra)
1413 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001414 /* Empty extcomm doesn't seem to be invalid per se */
1415 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001416 }
Paul Jakma0c466382010-12-05 17:17:26 +00001417
1418 (bgp_attr_extra_get (attr))->ecommunity =
1419 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1420 /* XXX: fix ecommunity_parse to use stream API */
1421 stream_forward_getp (peer->ibuf, length);
1422
1423 if (!attr->extra->ecommunity)
1424 return -1;
1425
paul718e3742002-12-13 20:15:29 +00001426 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1427
1428 return 0;
1429}
1430
1431/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001432static int
paul718e3742002-12-13 20:15:29 +00001433bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1434 u_char type, bgp_size_t length, u_char *startp)
1435{
1436 bgp_size_t total;
1437 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001438 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001439
hassof4184462005-02-01 20:13:16 +00001440 if (BGP_DEBUG (normal, NORMAL))
1441 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1442 peer->host, type, length);
1443
paul718e3742002-12-13 20:15:29 +00001444 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001445 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001446 "Unknown attribute type %d length %d is received", type, length);
1447
1448 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001449 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001450
1451 /* Adjest total length to include type and length. */
1452 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1453
1454 /* If any of the mandatory well-known attributes are not recognized,
1455 then the Error Subcode is set to Unrecognized Well-known
1456 Attribute. The Data field contains the unrecognized attribute
1457 (type, length and value). */
1458 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1459 {
1460 /* Adjust startp to do not include flag value. */
1461 bgp_notify_send_with_data (peer,
1462 BGP_NOTIFY_UPDATE_ERR,
1463 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1464 startp, total);
1465 return -1;
1466 }
1467
1468 /* Unrecognized non-transitive optional attributes must be quietly
1469 ignored and not passed along to other BGP peers. */
1470 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1471 return 0;
1472
1473 /* If a path with recognized transitive optional attribute is
1474 accepted and passed along to other BGP peers and the Partial bit
1475 in the Attribute Flags octet is set to 1 by some previous AS, it
1476 is not set back to 0 by the current AS. */
1477 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1478
1479 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001480 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001481 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001482
Paul Jakmafb982c22007-05-04 20:15:47 +00001483 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001484
1485 if (transit->val)
1486 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1487 transit->length + total);
1488 else
1489 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1490
1491 memcpy (transit->val + transit->length, startp, total);
1492 transit->length += total;
1493
1494 return 0;
1495}
1496
1497/* Read attribute of update packet. This function is called from
1498 bgp_update() in bgpd.c. */
1499int
1500bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1501 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1502{
1503 int ret;
1504 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001505 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001506 bgp_size_t length;
1507 u_char *startp, *endp;
1508 u_char *attr_endp;
1509 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001510 /* we need the as4_path only until we have synthesized the as_path with it */
1511 /* same goes for as4_aggregator */
1512 struct aspath *as4_path = NULL;
1513 as_t as4_aggregator = 0;
1514 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001515
1516 /* Initialize bitmap. */
1517 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1518
1519 /* End pointer of BGP attribute. */
1520 endp = BGP_INPUT_PNT (peer) + size;
1521
1522 /* Get attributes to the end of attribute length. */
1523 while (BGP_INPUT_PNT (peer) < endp)
1524 {
1525 /* Check remaining length check.*/
1526 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1527 {
gdtc29fdba2004-12-09 14:46:46 +00001528 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001529 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001530 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001531 peer->host,
1532 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001533
1534 bgp_notify_send (peer,
1535 BGP_NOTIFY_UPDATE_ERR,
1536 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1537 return -1;
1538 }
1539
1540 /* Fetch attribute flag and type. */
1541 startp = BGP_INPUT_PNT (peer);
1542 flag = stream_getc (BGP_INPUT (peer));
1543 type = stream_getc (BGP_INPUT (peer));
1544
Paul Jakma370b64a2007-12-22 16:49:52 +00001545 /* Check whether Extended-Length applies and is in bounds */
1546 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1547 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1548 {
1549 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001550 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001551 peer->host,
1552 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1553
1554 bgp_notify_send (peer,
1555 BGP_NOTIFY_UPDATE_ERR,
1556 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1557 return -1;
1558 }
1559
paul718e3742002-12-13 20:15:29 +00001560 /* Check extended attribue length bit. */
1561 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1562 length = stream_getw (BGP_INPUT (peer));
1563 else
1564 length = stream_getc (BGP_INPUT (peer));
1565
1566 /* If any attribute appears more than once in the UPDATE
1567 message, then the Error Subcode is set to Malformed Attribute
1568 List. */
1569
1570 if (CHECK_BITMAP (seen, type))
1571 {
1572 zlog (peer->log, LOG_WARNING,
1573 "%s error BGP attribute type %d appears twice in a message",
1574 peer->host, type);
1575
1576 bgp_notify_send (peer,
1577 BGP_NOTIFY_UPDATE_ERR,
1578 BGP_NOTIFY_UPDATE_MAL_ATTR);
1579 return -1;
1580 }
1581
1582 /* Set type to bitmap to check duplicate attribute. `type' is
1583 unsigned char so it never overflow bitmap range. */
1584
1585 SET_BITMAP (seen, type);
1586
1587 /* Overflow check. */
1588 attr_endp = BGP_INPUT_PNT (peer) + length;
1589
1590 if (attr_endp > endp)
1591 {
1592 zlog (peer->log, LOG_WARNING,
1593 "%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);
1594 bgp_notify_send (peer,
1595 BGP_NOTIFY_UPDATE_ERR,
1596 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1597 return -1;
1598 }
1599
1600 /* OK check attribute and store it's value. */
1601 switch (type)
1602 {
1603 case BGP_ATTR_ORIGIN:
1604 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1605 break;
1606 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001607 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001608 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001609 case BGP_ATTR_AS4_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001610 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001611 break;
paul718e3742002-12-13 20:15:29 +00001612 case BGP_ATTR_NEXT_HOP:
1613 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1614 break;
1615 case BGP_ATTR_MULTI_EXIT_DISC:
1616 ret = bgp_attr_med (peer, length, attr, flag, startp);
1617 break;
1618 case BGP_ATTR_LOCAL_PREF:
1619 ret = bgp_attr_local_pref (peer, length, attr, flag);
1620 break;
1621 case BGP_ATTR_ATOMIC_AGGREGATE:
1622 ret = bgp_attr_atomic (peer, length, attr, flag);
1623 break;
1624 case BGP_ATTR_AGGREGATOR:
1625 ret = bgp_attr_aggregator (peer, length, attr, flag);
1626 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001627 case BGP_ATTR_AS4_AGGREGATOR:
1628 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1629 break;
paul718e3742002-12-13 20:15:29 +00001630 case BGP_ATTR_COMMUNITIES:
1631 ret = bgp_attr_community (peer, length, attr, flag);
1632 break;
1633 case BGP_ATTR_ORIGINATOR_ID:
1634 ret = bgp_attr_originator_id (peer, length, attr, flag);
1635 break;
1636 case BGP_ATTR_CLUSTER_LIST:
1637 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1638 break;
1639 case BGP_ATTR_MP_REACH_NLRI:
1640 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1641 break;
1642 case BGP_ATTR_MP_UNREACH_NLRI:
1643 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1644 break;
1645 case BGP_ATTR_EXT_COMMUNITIES:
1646 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1647 break;
1648 default:
1649 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1650 break;
1651 }
1652
1653 /* If error occured immediately return to the caller. */
1654 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001655 {
1656 zlog (peer->log, LOG_WARNING,
1657 "%s: Attribute %s, parse error",
1658 peer->host,
1659 LOOKUP (attr_str, type));
1660 bgp_notify_send (peer,
1661 BGP_NOTIFY_UPDATE_ERR,
1662 BGP_NOTIFY_UPDATE_MAL_ATTR);
1663 return ret;
1664 }
paul718e3742002-12-13 20:15:29 +00001665
1666 /* Check the fetched length. */
1667 if (BGP_INPUT_PNT (peer) != attr_endp)
1668 {
1669 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001670 "%s: BGP attribute %s, fetch error",
1671 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001672 bgp_notify_send (peer,
1673 BGP_NOTIFY_UPDATE_ERR,
1674 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1675 return -1;
1676 }
1677 }
1678
1679 /* Check final read pointer is same as end pointer. */
1680 if (BGP_INPUT_PNT (peer) != endp)
1681 {
1682 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001683 "%s BGP attribute %s, length mismatch",
1684 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001685 bgp_notify_send (peer,
1686 BGP_NOTIFY_UPDATE_ERR,
1687 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1688 return -1;
1689 }
1690
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001691 /*
1692 * At this place we can see whether we got AS4_PATH and/or
1693 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1694 * We can not do this before we've read all attributes because
1695 * the as4 handling does not say whether AS4_PATH has to be sent
1696 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1697 * in relationship to AGGREGATOR.
1698 * So, to be defensive, we are not relying on any order and read
1699 * all attributes first, including these 32bit ones, and now,
1700 * afterwards, we look what and if something is to be done for as4.
1701 */
1702 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1703 as4_aggregator, &as4_aggregator_addr))
1704 return -1;
1705
1706 /* At this stage, we have done all fiddling with as4, and the
1707 * resulting info is in attr->aggregator resp. attr->aspath
1708 * so we can chuck as4_aggregator and as4_path alltogether in
1709 * order to save memory
1710 */
1711 if ( as4_path )
1712 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001713 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001714 /* The flag that we got this is still there, but that does not
1715 * do any trouble
1716 */
1717 }
1718 /*
1719 * The "rest" of the code does nothing with as4_aggregator.
1720 * there is no memory attached specifically which is not part
1721 * of the attr.
1722 * so ignoring just means do nothing.
1723 */
1724 /*
1725 * Finally do the checks on the aspath we did not do yet
1726 * because we waited for a potentially synthesized aspath.
1727 */
1728 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1729 {
1730 ret = bgp_attr_aspath_check( peer, attr );
1731 if ( ret < 0 )
1732 return ret;
1733 }
1734
paul718e3742002-12-13 20:15:29 +00001735 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001736 if (attr->extra && attr->extra->transit)
1737 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001738
1739 return 0;
1740}
1741
1742/* Well-known attribute check. */
1743int
1744bgp_attr_check (struct peer *peer, struct attr *attr)
1745{
1746 u_char type = 0;
1747
1748 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1749 type = BGP_ATTR_ORIGIN;
1750
1751 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1752 type = BGP_ATTR_AS_PATH;
1753
1754 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1755 type = BGP_ATTR_NEXT_HOP;
1756
1757 if (peer_sort (peer) == BGP_PEER_IBGP
1758 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1759 type = BGP_ATTR_LOCAL_PREF;
1760
1761 if (type)
1762 {
1763 zlog (peer->log, LOG_WARNING,
1764 "%s Missing well-known attribute %d.",
1765 peer->host, type);
1766 bgp_notify_send_with_data (peer,
1767 BGP_NOTIFY_UPDATE_ERR,
1768 BGP_NOTIFY_UPDATE_MISS_ATTR,
1769 &type, 1);
1770 return -1;
1771 }
1772 return 0;
1773}
1774
1775int stream_put_prefix (struct stream *, struct prefix *);
1776
1777/* Make attribute packet. */
1778bgp_size_t
1779bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1780 struct stream *s, struct attr *attr, struct prefix *p,
1781 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001782 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001783{
paulfe69a502005-09-10 16:55:02 +00001784 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001785 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001786 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001787 int send_as4_path = 0;
1788 int send_as4_aggregator = 0;
1789 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001790
1791 if (! bgp)
1792 bgp = bgp_get_default ();
1793
1794 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001795 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001796
1797 /* Origin attribute. */
1798 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1799 stream_putc (s, BGP_ATTR_ORIGIN);
1800 stream_putc (s, 1);
1801 stream_putc (s, attr->origin);
1802
1803 /* AS path attribute. */
1804
1805 /* If remote-peer is EBGP */
1806 if (peer_sort (peer) == BGP_PEER_EBGP
1807 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001808 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001809 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001810 {
1811 aspath = aspath_dup (attr->aspath);
1812
1813 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1814 {
1815 /* Strip the confed info, and then stuff our path CONFED_ID
1816 on the front */
1817 aspath = aspath_delete_confed_seq (aspath);
1818 aspath = aspath_add_seq (aspath, bgp->confed_id);
1819 }
1820 else
1821 {
1822 aspath = aspath_add_seq (aspath, peer->local_as);
1823 if (peer->change_local_as)
1824 aspath = aspath_add_seq (aspath, peer->change_local_as);
1825 }
1826 }
1827 else if (peer_sort (peer) == BGP_PEER_CONFED)
1828 {
1829 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1830 aspath = aspath_dup (attr->aspath);
1831 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1832 }
1833 else
1834 aspath = attr->aspath;
1835
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001836 /* If peer is not AS4 capable, then:
1837 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1838 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1839 * types are in it (i.e. exclude them if they are there)
1840 * AND do this only if there is at least one asnum > 65535 in the path!
1841 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1842 * all ASnums > 65535 to BGP_AS_TRANS
1843 */
paul718e3742002-12-13 20:15:29 +00001844
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001845 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1846 stream_putc (s, BGP_ATTR_AS_PATH);
1847 aspath_sizep = stream_get_endp (s);
1848 stream_putw (s, 0);
1849 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1850
1851 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1852 * in the path
1853 */
1854 if (!use32bit && aspath_has_as4 (aspath))
1855 send_as4_path = 1; /* we'll do this later, at the correct place */
1856
paul718e3742002-12-13 20:15:29 +00001857 /* Nexthop attribute. */
1858 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1859 {
1860 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1861 stream_putc (s, BGP_ATTR_NEXT_HOP);
1862 stream_putc (s, 4);
1863 if (safi == SAFI_MPLS_VPN)
1864 {
1865 if (attr->nexthop.s_addr == 0)
1866 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1867 else
1868 stream_put_ipv4 (s, attr->nexthop.s_addr);
1869 }
1870 else
1871 stream_put_ipv4 (s, attr->nexthop.s_addr);
1872 }
1873
1874 /* MED attribute. */
1875 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1876 {
1877 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1878 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1879 stream_putc (s, 4);
1880 stream_putl (s, attr->med);
1881 }
1882
1883 /* Local preference. */
1884 if (peer_sort (peer) == BGP_PEER_IBGP ||
1885 peer_sort (peer) == BGP_PEER_CONFED)
1886 {
1887 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1888 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1889 stream_putc (s, 4);
1890 stream_putl (s, attr->local_pref);
1891 }
1892
1893 /* Atomic aggregate. */
1894 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1895 {
1896 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1897 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1898 stream_putc (s, 0);
1899 }
1900
1901 /* Aggregator. */
1902 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1903 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001904 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001905
1906 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001907 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1908 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001909
1910 if (use32bit)
1911 {
1912 /* AS4 capable peer */
1913 stream_putc (s, 8);
1914 stream_putl (s, attr->extra->aggregator_as);
1915 }
1916 else
1917 {
1918 /* 2-byte AS peer */
1919 stream_putc (s, 6);
1920
1921 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1922 if ( attr->extra->aggregator_as > 65535 )
1923 {
1924 stream_putw (s, BGP_AS_TRANS);
1925
1926 /* we have to send AS4_AGGREGATOR, too.
1927 * we'll do that later in order to send attributes in ascending
1928 * order.
1929 */
1930 send_as4_aggregator = 1;
1931 }
1932 else
1933 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1934 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001935 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001936 }
1937
1938 /* Community attribute. */
1939 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1940 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1941 {
1942 if (attr->community->size * 4 > 255)
1943 {
1944 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1945 stream_putc (s, BGP_ATTR_COMMUNITIES);
1946 stream_putw (s, attr->community->size * 4);
1947 }
1948 else
1949 {
1950 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1951 stream_putc (s, BGP_ATTR_COMMUNITIES);
1952 stream_putc (s, attr->community->size * 4);
1953 }
1954 stream_put (s, attr->community->val, attr->community->size * 4);
1955 }
1956
1957 /* Route Reflector. */
1958 if (peer_sort (peer) == BGP_PEER_IBGP
1959 && from
1960 && peer_sort (from) == BGP_PEER_IBGP)
1961 {
1962 /* Originator ID. */
1963 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1964 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1965 stream_putc (s, 4);
1966
1967 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001968 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001969 else
1970 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001971
1972 /* Cluster list. */
1973 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1974 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1975
Paul Jakma9eda90c2007-08-30 13:36:17 +00001976 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001977 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001978 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001979 /* If this peer configuration's parent BGP has cluster_id. */
1980 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1981 stream_put_in_addr (s, &bgp->cluster_id);
1982 else
1983 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001984 stream_put (s, attr->extra->cluster->list,
1985 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001986 }
1987 else
1988 {
1989 stream_putc (s, 4);
1990 /* If this peer configuration's parent BGP has cluster_id. */
1991 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1992 stream_put_in_addr (s, &bgp->cluster_id);
1993 else
1994 stream_put_in_addr (s, &bgp->router_id);
1995 }
1996 }
1997
1998#ifdef HAVE_IPV6
1999 /* If p is IPv6 address put it into attribute. */
2000 if (p->family == AF_INET6)
2001 {
2002 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002003 struct attr_extra *attre = attr->extra;
2004
2005 assert (attr->extra);
2006
paul718e3742002-12-13 20:15:29 +00002007 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2008 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002009 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002010 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002011 stream_putw (s, AFI_IP6); /* AFI */
2012 stream_putc (s, safi); /* SAFI */
2013
Paul Jakmafb982c22007-05-04 20:15:47 +00002014 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002015
Paul Jakmafb982c22007-05-04 20:15:47 +00002016 if (attre->mp_nexthop_len == 16)
2017 stream_put (s, &attre->mp_nexthop_global, 16);
2018 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002019 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002020 stream_put (s, &attre->mp_nexthop_global, 16);
2021 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002022 }
2023
2024 /* SNPA */
2025 stream_putc (s, 0);
2026
paul718e3742002-12-13 20:15:29 +00002027 /* Prefix write. */
2028 stream_put_prefix (s, p);
2029
2030 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002031 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002032 }
2033#endif /* HAVE_IPV6 */
2034
2035 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2036 {
2037 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002038
2039 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2040 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002041 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002042 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002043 stream_putw (s, AFI_IP); /* AFI */
2044 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2045
2046 stream_putc (s, 4);
2047 stream_put_ipv4 (s, attr->nexthop.s_addr);
2048
2049 /* SNPA */
2050 stream_putc (s, 0);
2051
paul718e3742002-12-13 20:15:29 +00002052 /* Prefix write. */
2053 stream_put_prefix (s, p);
2054
2055 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002056 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002057 }
2058
2059 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2060 {
2061 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002062
2063 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2064 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002065 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002066 stream_putc (s, 0); /* Length of this attribute. */
2067 stream_putw (s, AFI_IP); /* AFI */
2068 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2069
2070 stream_putc (s, 12);
2071 stream_putl (s, 0);
2072 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002073 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002074
2075 /* SNPA */
2076 stream_putc (s, 0);
2077
paul718e3742002-12-13 20:15:29 +00002078 /* Tag, RD, Prefix write. */
2079 stream_putc (s, p->prefixlen + 88);
2080 stream_put (s, tag, 3);
2081 stream_put (s, prd->val, 8);
2082 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2083
2084 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002085 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002086 }
2087
2088 /* Extended Communities attribute. */
2089 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2090 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2091 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002092 struct attr_extra *attre = attr->extra;
2093
2094 assert (attre);
2095
2096 if (peer_sort (peer) == BGP_PEER_IBGP
2097 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002098 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002099 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002100 {
2101 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2102 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002103 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002104 }
2105 else
2106 {
2107 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2108 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002109 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002110 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002111 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002112 }
2113 else
2114 {
paul5228ad22004-06-04 17:58:18 +00002115 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002116 int tbit;
2117 int ecom_tr_size = 0;
2118 int i;
2119
Paul Jakmafb982c22007-05-04 20:15:47 +00002120 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002121 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002122 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002123 tbit = *pnt;
2124
2125 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2126 continue;
2127
2128 ecom_tr_size++;
2129 }
2130
2131 if (ecom_tr_size)
2132 {
2133 if (ecom_tr_size * 8 > 255)
2134 {
2135 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2136 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2137 stream_putw (s, ecom_tr_size * 8);
2138 }
2139 else
2140 {
2141 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2142 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2143 stream_putc (s, ecom_tr_size * 8);
2144 }
2145
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002147 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002148 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002149 tbit = *pnt;
2150
2151 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2152 continue;
2153
2154 stream_put (s, pnt, 8);
2155 }
2156 }
paul718e3742002-12-13 20:15:29 +00002157 }
paul718e3742002-12-13 20:15:29 +00002158 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002159
2160 if ( send_as4_path )
2161 {
2162 /* If the peer is NOT As4 capable, AND */
2163 /* there are ASnums > 65535 in path THEN
2164 * give out AS4_PATH */
2165
2166 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2167 * path segments!
2168 * Hm, I wonder... confederation things *should* only be at
2169 * the beginning of an aspath, right? Then we should use
2170 * aspath_delete_confed_seq for this, because it is already
2171 * there! (JK)
2172 * Folks, talk to me: what is reasonable here!?
2173 */
2174 aspath = aspath_delete_confed_seq (aspath);
2175
2176 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2177 stream_putc (s, BGP_ATTR_AS4_PATH);
2178 aspath_sizep = stream_get_endp (s);
2179 stream_putw (s, 0);
2180 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2181 }
2182
2183 if (aspath != attr->aspath)
2184 aspath_free (aspath);
2185
2186 if ( send_as4_aggregator )
2187 {
2188 assert (attr->extra);
2189
2190 /* send AS4_AGGREGATOR, at this place */
2191 /* this section of code moved here in order to ensure the correct
2192 * *ascending* order of attributes
2193 */
2194 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2195 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2196 stream_putc (s, 8);
2197 stream_putl (s, attr->extra->aggregator_as);
2198 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2199 }
Paul Jakma41367172007-08-06 15:24:51 +00002200
paul718e3742002-12-13 20:15:29 +00002201 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002202 if (attr->extra && attr->extra->transit)
2203 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002204
2205 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002206 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002207}
2208
2209bgp_size_t
2210bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2211 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002212 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002213{
2214 unsigned long cp;
2215 unsigned long attrlen_pnt;
2216 bgp_size_t size;
2217
paul9985f832005-02-09 15:51:56 +00002218 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002219
2220 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2221 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2222
paul9985f832005-02-09 15:51:56 +00002223 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002224 stream_putc (s, 0); /* Length of this attribute. */
2225
2226 stream_putw (s, family2afi (p->family));
2227
2228 if (safi == SAFI_MPLS_VPN)
2229 {
2230 /* SAFI */
2231 stream_putc (s, BGP_SAFI_VPNV4);
2232
2233 /* prefix. */
2234 stream_putc (s, p->prefixlen + 88);
2235 stream_put (s, tag, 3);
2236 stream_put (s, prd->val, 8);
2237 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2238 }
2239 else
2240 {
2241 /* SAFI */
2242 stream_putc (s, safi);
2243
2244 /* prefix */
2245 stream_put_prefix (s, p);
2246 }
2247
2248 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002249 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002250 stream_putc_at (s, attrlen_pnt, size);
2251
paul9985f832005-02-09 15:51:56 +00002252 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002253}
2254
2255/* Initialization of attribute. */
2256void
paulfe69a502005-09-10 16:55:02 +00002257bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002258{
paul718e3742002-12-13 20:15:29 +00002259 aspath_init ();
2260 attrhash_init ();
2261 community_init ();
2262 ecommunity_init ();
2263 cluster_init ();
2264 transit_init ();
2265}
2266
Chris Caputo228da422009-07-18 05:44:03 +00002267void
2268bgp_attr_finish (void)
2269{
2270 aspath_finish ();
2271 attrhash_finish ();
2272 community_finish ();
2273 ecommunity_finish ();
2274 cluster_finish ();
2275 transit_finish ();
2276}
2277
paul718e3742002-12-13 20:15:29 +00002278/* Make attribute packet. */
2279void
paula3845922003-10-18 01:30:50 +00002280bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2281 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002282{
2283 unsigned long cp;
2284 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002285 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002286 struct aspath *aspath;
2287
2288 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002289 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002290
2291 /* Place holder of length. */
2292 stream_putw (s, 0);
2293
2294 /* Origin attribute. */
2295 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2296 stream_putc (s, BGP_ATTR_ORIGIN);
2297 stream_putc (s, 1);
2298 stream_putc (s, attr->origin);
2299
2300 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002301
2302 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2303 stream_putc (s, BGP_ATTR_AS_PATH);
2304 aspath_lenp = stream_get_endp (s);
2305 stream_putw (s, 0);
2306
2307 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002308
2309 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002310 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2311 if(prefix != NULL
2312#ifdef HAVE_IPV6
2313 && prefix->family != AF_INET6
2314#endif /* HAVE_IPV6 */
2315 )
2316 {
2317 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2318 stream_putc (s, BGP_ATTR_NEXT_HOP);
2319 stream_putc (s, 4);
2320 stream_put_ipv4 (s, attr->nexthop.s_addr);
2321 }
paul718e3742002-12-13 20:15:29 +00002322
2323 /* MED attribute. */
2324 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2325 {
2326 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2327 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2328 stream_putc (s, 4);
2329 stream_putl (s, attr->med);
2330 }
2331
2332 /* Local preference. */
2333 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2334 {
2335 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2336 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2337 stream_putc (s, 4);
2338 stream_putl (s, attr->local_pref);
2339 }
2340
2341 /* Atomic aggregate. */
2342 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2343 {
2344 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2345 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2346 stream_putc (s, 0);
2347 }
2348
2349 /* Aggregator. */
2350 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2351 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002352 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002353 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2354 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002355 stream_putc (s, 8);
2356 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002357 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002358 }
2359
2360 /* Community attribute. */
2361 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2362 {
2363 if (attr->community->size * 4 > 255)
2364 {
2365 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2366 stream_putc (s, BGP_ATTR_COMMUNITIES);
2367 stream_putw (s, attr->community->size * 4);
2368 }
2369 else
2370 {
2371 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2372 stream_putc (s, BGP_ATTR_COMMUNITIES);
2373 stream_putc (s, attr->community->size * 4);
2374 }
2375 stream_put (s, attr->community->val, attr->community->size * 4);
2376 }
2377
paula3845922003-10-18 01:30:50 +00002378#ifdef HAVE_IPV6
2379 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002380 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2381 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002382 {
2383 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002384 struct attr_extra *attre = attr->extra;
2385
paula3845922003-10-18 01:30:50 +00002386 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2387 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002388 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002389
2390 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002391 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002392 stream_putw(s, AFI_IP6); /* AFI */
2393 stream_putc(s, SAFI_UNICAST); /* SAFI */
2394
2395 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002396 stream_putc(s, attre->mp_nexthop_len);
2397 stream_put(s, &attre->mp_nexthop_global, 16);
2398 if (attre->mp_nexthop_len == 32)
2399 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002400
2401 /* SNPA */
2402 stream_putc(s, 0);
2403
2404 /* Prefix */
2405 stream_put_prefix(s, prefix);
2406
2407 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002408 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002409 }
2410#endif /* HAVE_IPV6 */
2411
paul718e3742002-12-13 20:15:29 +00002412 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002413 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002414 stream_putw_at (s, cp, len);
2415}