blob: 01598c87b44c1367414ecc4c6eac47a702ea9c0f [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++;
503 }
504 if (attre->cluster)
505 {
506 if (! attre->cluster->refcnt)
507 attre->cluster = cluster_intern (attre->cluster);
508 else
509 attre->cluster->refcnt++;
510 }
511 if (attre->transit)
512 {
513 if (! attre->transit->refcnt)
514 attre->transit = transit_intern (attre->transit);
515 else
516 attre->transit->refcnt++;
517 }
paul718e3742002-12-13 20:15:29 +0000518 }
519
520 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
521 find->refcnt++;
522
523 return find;
524}
525
Paul Jakma03e214c2007-04-29 18:31:07 +0000526
paul718e3742002-12-13 20:15:29 +0000527/* Make network statement's attribute. */
528struct attr *
529bgp_attr_default_set (struct attr *attr, u_char origin)
530{
531 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000532 bgp_attr_extra_get (attr);
533
paul718e3742002-12-13 20:15:29 +0000534 attr->origin = origin;
535 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
536 attr->aspath = aspath_empty ();
537 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000538 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000539 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
540#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000541 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000542#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544 return attr;
545}
546
Paul Jakma03e214c2007-04-29 18:31:07 +0000547
paul718e3742002-12-13 20:15:29 +0000548/* Make network statement's attribute. */
549struct attr *
550bgp_attr_default_intern (u_char origin)
551{
552 struct attr attr;
553 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000554 struct attr_extra *attre;
555
556 memset (&attr, 0, sizeof (struct attr));
557 attre = bgp_attr_extra_get (&attr);
558
Paul Jakma03e214c2007-04-29 18:31:07 +0000559 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000560
561 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000562 bgp_attr_extra_free (&attr);
563
paul718e3742002-12-13 20:15:29 +0000564 aspath_unintern (new->aspath);
565 return new;
566}
567
568struct attr *
569bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
570 struct aspath *aspath,
571 struct community *community, int as_set)
572{
573 struct attr attr;
574 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000575 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000576
577 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000578 attre = bgp_attr_extra_get (&attr);
579
paul718e3742002-12-13 20:15:29 +0000580 /* Origin attribute. */
581 attr.origin = origin;
582 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
583
584 /* AS path attribute. */
585 if (aspath)
586 attr.aspath = aspath_intern (aspath);
587 else
588 attr.aspath = aspath_empty ();
589 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
590
591 /* Next hop attribute. */
592 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
593
594 if (community)
595 {
596 attr.community = community;
597 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
598 }
599
Paul Jakmafb982c22007-05-04 20:15:47 +0000600 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000601#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000602 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000603#endif
604 if (! as_set)
605 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
607 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000608 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000609 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000610 attre->aggregator_as = bgp->as;
611 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000612
613 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000614 bgp_attr_extra_free (&attr);
615
paul718e3742002-12-13 20:15:29 +0000616 aspath_unintern (new->aspath);
617 return new;
618}
619
620/* Free bgp attribute and aspath. */
621void
622bgp_attr_unintern (struct attr *attr)
623{
624 struct attr *ret;
625 struct aspath *aspath;
626 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 struct ecommunity *ecommunity = NULL;
628 struct cluster_list *cluster = NULL;
629 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000630
631 /* Decrement attribute reference. */
632 attr->refcnt--;
633 aspath = attr->aspath;
634 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000635 if (attr->extra)
636 {
637 ecommunity = attr->extra->ecommunity;
638 cluster = attr->extra->cluster;
639 transit = attr->extra->transit;
640 }
paul718e3742002-12-13 20:15:29 +0000641
642 /* If reference becomes zero then free attribute object. */
643 if (attr->refcnt == 0)
644 {
645 ret = hash_release (attrhash, attr);
646 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000647 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000648 XFREE (MTYPE_ATTR, attr);
649 }
650
651 /* aspath refcount shoud be decrement. */
652 if (aspath)
653 aspath_unintern (aspath);
654 if (community)
655 community_unintern (community);
656 if (ecommunity)
657 ecommunity_unintern (ecommunity);
658 if (cluster)
659 cluster_unintern (cluster);
660 if (transit)
661 transit_unintern (transit);
662}
663
664void
665bgp_attr_flush (struct attr *attr)
666{
667 if (attr->aspath && ! attr->aspath->refcnt)
668 aspath_free (attr->aspath);
669 if (attr->community && ! attr->community->refcnt)
670 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 if (attr->extra)
672 {
673 struct attr_extra *attre = attr->extra;
674 if (attre->ecommunity && ! attre->ecommunity->refcnt)
675 ecommunity_free (attre->ecommunity);
676 if (attre->cluster && ! attre->cluster->refcnt)
677 cluster_free (attre->cluster);
678 if (attre->transit && ! attre->transit->refcnt)
679 transit_free (attre->transit);
680 }
paul718e3742002-12-13 20:15:29 +0000681}
682
683/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000684static int
paul718e3742002-12-13 20:15:29 +0000685bgp_attr_origin (struct peer *peer, bgp_size_t length,
686 struct attr *attr, u_char flag, u_char *startp)
687{
688 bgp_size_t total;
689
690 /* total is entire attribute length include Attribute Flags (1),
691 Attribute Type code (1) and Attribute length (1 or 2). */
692 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
693
694 /* If any recognized attribute has Attribute Flags that conflict
695 with the Attribute Type Code, then the Error Subcode is set to
696 Attribute Flags Error. The Data field contains the erroneous
697 attribute (type, length and value). */
698 if (flag != BGP_ATTR_FLAG_TRANS)
699 {
700 zlog (peer->log, LOG_ERR,
701 "Origin attribute flag isn't transitive %d", flag);
702 bgp_notify_send_with_data (peer,
703 BGP_NOTIFY_UPDATE_ERR,
704 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
705 startp, total);
706 return -1;
707 }
708
709 /* If any recognized attribute has Attribute Length that conflicts
710 with the expected length (based on the attribute type code), then
711 the Error Subcode is set to Attribute Length Error. The Data
712 field contains the erroneous attribute (type, length and
713 value). */
714 if (length != 1)
715 {
716 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
717 length);
718 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
719 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
720 startp, total);
721 return -1;
722 }
723
724 /* Fetch origin attribute. */
725 attr->origin = stream_getc (BGP_INPUT (peer));
726
727 /* If the ORIGIN attribute has an undefined value, then the Error
728 Subcode is set to Invalid Origin Attribute. The Data field
729 contains the unrecognized attribute (type, length and value). */
730 if ((attr->origin != BGP_ORIGIN_IGP)
731 && (attr->origin != BGP_ORIGIN_EGP)
732 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
733 {
734 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
735 attr->origin);
736
737 bgp_notify_send_with_data (peer,
738 BGP_NOTIFY_UPDATE_ERR,
739 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
740 startp, total);
741 return -1;
742 }
743
744 /* Set oring attribute flag. */
745 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
746
747 return 0;
748}
Chris Hallcddb8112010-08-09 22:31:37 +0400749/* Parse AS path information. This function is wrapper of aspath_parse.
750 *
751 * Parses AS_PATH or AS4_PATH.
752 *
753 * Returns: if valid: address of struct aspath in the hash of known aspaths,
754 * with reference count incremented.
755 * else: NULL
756 *
757 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
758 * have segments == NULL and str == zero length string (unique).
759 */
760static struct aspath *
paul718e3742002-12-13 20:15:29 +0000761bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400762 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000763{
Chris Hallcddb8112010-08-09 22:31:37 +0400764 u_char require ;
765 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000766
Chris Hallcddb8112010-08-09 22:31:37 +0400767 /* Check the attribute flags */
768 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
769 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000770
Chris Hallcddb8112010-08-09 22:31:37 +0400771 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000772 {
Chris Hallcddb8112010-08-09 22:31:37 +0400773 const char* path_type ;
774 bgp_size_t total;
775
776 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
777
778 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000779 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400780 "%s attribute flag isn't transitive %d", path_type, flag) ;
781
782 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
783 zlog (peer->log, LOG_ERR,
784 "%s attribute flag must %sbe optional %d", path_type,
785 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
786
787 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
788
paul718e3742002-12-13 20:15:29 +0000789 bgp_notify_send_with_data (peer,
790 BGP_NOTIFY_UPDATE_ERR,
791 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
792 startp, total);
paul718e3742002-12-13 20:15:29 +0000793
Chris Hallcddb8112010-08-09 22:31:37 +0400794 return NULL ;
795 } ;
796
797 /* Parse the AS_PATH/AS4_PATH body.
798 *
799 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
800 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000801 */
Chris Hallcddb8112010-08-09 22:31:37 +0400802 asp = aspath_parse (peer->ibuf, length,
803 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000804
Chris Hallcddb8112010-08-09 22:31:37 +0400805 if (asp != NULL)
806 {
807 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
808 : BGP_ATTR_AS_PATH) ;
809 }
810 else
paul718e3742002-12-13 20:15:29 +0000811 {
812 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400813
814 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000815 bgp_notify_send (peer,
816 BGP_NOTIFY_UPDATE_ERR,
817 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400818 } ;
paul718e3742002-12-13 20:15:29 +0000819
Chris Hallcddb8112010-08-09 22:31:37 +0400820 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000821}
822
823static int bgp_attr_aspath_check( struct peer *peer,
824 struct attr *attr)
825{
826 /* These checks were part of bgp_attr_aspath, but with
827 * as4 we should to check aspath things when
828 * aspath synthesizing with as4_path has already taken place.
829 * Otherwise we check ASPATH and use the synthesized thing, and that is
830 * not right.
831 * So do the checks later, i.e. here
832 */
833 struct bgp *bgp = peer->bgp;
834 struct aspath *aspath;
835
paul718e3742002-12-13 20:15:29 +0000836 bgp = peer->bgp;
837
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300838 /* Confederation sanity check. */
839 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
840 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
841 {
842 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
843 bgp_notify_send (peer,
844 BGP_NOTIFY_UPDATE_ERR,
845 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
846 return -1;
847 }
848
paul718e3742002-12-13 20:15:29 +0000849 /* First AS check for EBGP. */
850 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
851 {
852 if (peer_sort (peer) == BGP_PEER_EBGP
853 && ! aspath_firstas_check (attr->aspath, peer->as))
854 {
855 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400856 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000857 bgp_notify_send (peer,
858 BGP_NOTIFY_UPDATE_ERR,
859 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
860 return -1;
861 }
862 }
863
864 /* local-as prepend */
865 if (peer->change_local_as &&
866 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
867 {
868 aspath = aspath_dup (attr->aspath);
869 aspath = aspath_add_seq (aspath, peer->change_local_as);
870 aspath_unintern (attr->aspath);
871 attr->aspath = aspath_intern (aspath);
872 }
873
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000874 return 0;
875
876}
877
paul718e3742002-12-13 20:15:29 +0000878/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000879static int
paul718e3742002-12-13 20:15:29 +0000880bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
881 struct attr *attr, u_char flag, u_char *startp)
882{
883 bgp_size_t total;
884
885 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
886
887 /* Flag check. */
888 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
889 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
890 {
891 zlog (peer->log, LOG_ERR,
892 "Origin attribute flag isn't transitive %d", flag);
893 bgp_notify_send_with_data (peer,
894 BGP_NOTIFY_UPDATE_ERR,
895 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
896 startp, total);
897 return -1;
898 }
899
900 /* Check nexthop attribute length. */
901 if (length != 4)
902 {
903 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
904 length);
905
906 bgp_notify_send_with_data (peer,
907 BGP_NOTIFY_UPDATE_ERR,
908 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
909 startp, total);
910 return -1;
911 }
912
913 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
914 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
915
916 return 0;
917}
918
919/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000920static int
paul718e3742002-12-13 20:15:29 +0000921bgp_attr_med (struct peer *peer, bgp_size_t length,
922 struct attr *attr, u_char flag, u_char *startp)
923{
924 bgp_size_t total;
925
926 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
927
928 /* Length check. */
929 if (length != 4)
930 {
931 zlog (peer->log, LOG_ERR,
932 "MED attribute length isn't four [%d]", length);
933
934 bgp_notify_send_with_data (peer,
935 BGP_NOTIFY_UPDATE_ERR,
936 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
937 startp, total);
938 return -1;
939 }
940
941 attr->med = stream_getl (peer->ibuf);
942
943 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
944
945 return 0;
946}
947
948/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000949static int
paul718e3742002-12-13 20:15:29 +0000950bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
951 struct attr *attr, u_char flag)
952{
953 /* If it is contained in an UPDATE message that is received from an
954 external peer, then this attribute MUST be ignored by the
955 receiving speaker. */
956 if (peer_sort (peer) == BGP_PEER_EBGP)
957 {
paul9985f832005-02-09 15:51:56 +0000958 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000959 return 0;
960 }
961
962 if (length == 4)
963 attr->local_pref = stream_getl (peer->ibuf);
964 else
965 attr->local_pref = 0;
966
967 /* Set atomic aggregate flag. */
968 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
969
970 return 0;
971}
972
973/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000974static int
paul718e3742002-12-13 20:15:29 +0000975bgp_attr_atomic (struct peer *peer, bgp_size_t length,
976 struct attr *attr, u_char flag)
977{
978 if (length != 0)
979 {
980 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
981
982 bgp_notify_send (peer,
983 BGP_NOTIFY_UPDATE_ERR,
984 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
985 return -1;
986 }
987
988 /* Set atomic aggregate flag. */
989 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
990
991 return 0;
992}
993
994/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000995static int
paul718e3742002-12-13 20:15:29 +0000996bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
997 struct attr *attr, u_char flag)
998{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000999 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001000 struct attr_extra *attre = bgp_attr_extra_get (attr);
1001
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001002 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1003 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1004 wantedlen = 8;
1005
1006 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001007 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001008 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001009
1010 bgp_notify_send (peer,
1011 BGP_NOTIFY_UPDATE_ERR,
1012 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1013 return -1;
1014 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001015
1016 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1017 attre->aggregator_as = stream_getl (peer->ibuf);
1018 else
1019 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001020 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001021
1022 /* Set atomic aggregate flag. */
1023 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1024
1025 return 0;
1026}
1027
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001028/* New Aggregator attribute */
1029static int
1030bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1031 struct attr *attr, as_t *as4_aggregator_as,
1032 struct in_addr *as4_aggregator_addr)
1033{
1034 if (length != 8)
1035 {
1036 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1037
1038 bgp_notify_send (peer,
1039 BGP_NOTIFY_UPDATE_ERR,
1040 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1041 return -1;
1042 }
1043 *as4_aggregator_as = stream_getl (peer->ibuf);
1044 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1045
1046 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1047
1048 return 0;
1049}
1050
1051/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1052 */
1053static int
1054bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1055 struct aspath *as4_path, as_t as4_aggregator,
1056 struct in_addr *as4_aggregator_addr)
1057{
1058 int ignore_as4_path = 0;
1059 struct aspath *newpath;
1060 struct attr_extra *attre = attr->extra;
1061
1062 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1063 {
1064 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1065 * if given.
1066 * It is worth a warning though, because the peer really
1067 * should not send them
1068 */
1069 if (BGP_DEBUG(as4, AS4))
1070 {
1071 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1072 zlog_debug ("[AS4] %s %s AS4_PATH",
1073 peer->host, "AS4 capable peer, yet it sent");
1074
1075 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1076 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1077 peer->host, "AS4 capable peer, yet it sent");
1078 }
1079
1080 return 0;
1081 }
1082
1083 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1084 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1085 {
1086 /* Hu? This is not supposed to happen at all!
1087 * got as4_path and no aspath,
1088 * This should already
1089 * have been handled by 'well known attributes missing'
1090 * But... yeah, paranoia
1091 * Take this as a "malformed attribute"
1092 */
1093 zlog (peer->log, LOG_ERR,
1094 "%s BGP not AS4 capable peer sent AS4_PATH but"
1095 " no AS_PATH, cant do anything here", peer->host);
1096 bgp_notify_send (peer,
1097 BGP_NOTIFY_UPDATE_ERR,
1098 BGP_NOTIFY_UPDATE_MAL_ATTR);
1099 return -1;
1100 }
1101
1102 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1103 * because that may override AS4_PATH
1104 */
1105 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1106 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001107 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1108 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001109 assert (attre);
1110
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001111 /* received both.
1112 * if the as_number in aggregator is not AS_TRANS,
1113 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1114 * and the Aggregator shall be taken as
1115 * info on the aggregating node, and the AS_PATH
1116 * shall be taken as the AS_PATH
1117 * otherwise
1118 * the Aggregator shall be ignored and the
1119 * AS4_AGGREGATOR shall be taken as the
1120 * Aggregating node and the AS_PATH is to be
1121 * constructed "as in all other cases"
1122 */
1123 if ( attre->aggregator_as != BGP_AS_TRANS )
1124 {
1125 /* ignore */
1126 if ( BGP_DEBUG(as4, AS4))
1127 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1128 " send AGGREGATOR != AS_TRANS and"
1129 " AS4_AGGREGATOR, so ignore"
1130 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1131 ignore_as4_path = 1;
1132 }
1133 else
1134 {
1135 /* "New_aggregator shall be taken as aggregator" */
1136 attre->aggregator_as = as4_aggregator;
1137 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1138 }
1139 }
1140 else
1141 {
1142 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1143 * That is bogus - but reading the conditions
1144 * we have to handle AS4_AGGREGATOR as if it were
1145 * AGGREGATOR in that case
1146 */
1147 if ( BGP_DEBUG(as4, AS4))
1148 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1149 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1150 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001151 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001152 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1153 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1154 }
1155 }
1156
1157 /* need to reconcile NEW_AS_PATH and AS_PATH */
1158 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1159 {
1160 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1161 aspath_unintern (attr->aspath);
1162 attr->aspath = aspath_intern (newpath);
1163 }
1164 return 0;
1165}
1166
paul718e3742002-12-13 20:15:29 +00001167/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001168static int
paul718e3742002-12-13 20:15:29 +00001169bgp_attr_community (struct peer *peer, bgp_size_t length,
1170 struct attr *attr, u_char flag)
1171{
1172 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001173 {
1174 attr->community = NULL;
1175 return 0;
1176 }
Paul Jakma0c466382010-12-05 17:17:26 +00001177
1178 attr->community =
1179 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1180
1181 /* XXX: fix community_parse to use stream API and remove this */
1182 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001183
Paul Jakma0c466382010-12-05 17:17:26 +00001184 if (!attr->community)
1185 return -1;
1186
paul718e3742002-12-13 20:15:29 +00001187 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1188
1189 return 0;
1190}
1191
1192/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001193static int
paul718e3742002-12-13 20:15:29 +00001194bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1195 struct attr *attr, u_char flag)
1196{
1197 if (length != 4)
1198 {
1199 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1200
1201 bgp_notify_send (peer,
1202 BGP_NOTIFY_UPDATE_ERR,
1203 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1204 return -1;
1205 }
1206
Paul Jakmafb982c22007-05-04 20:15:47 +00001207 (bgp_attr_extra_get (attr))->originator_id.s_addr
1208 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001209
1210 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1211
1212 return 0;
1213}
1214
1215/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001216static int
paul718e3742002-12-13 20:15:29 +00001217bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1218 struct attr *attr, u_char flag)
1219{
1220 /* Check length. */
1221 if (length % 4)
1222 {
1223 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1224
1225 bgp_notify_send (peer,
1226 BGP_NOTIFY_UPDATE_ERR,
1227 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1228 return -1;
1229 }
1230
Paul Jakmafb982c22007-05-04 20:15:47 +00001231 (bgp_attr_extra_get (attr))->cluster
1232 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001233
paul9985f832005-02-09 15:51:56 +00001234 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001235
1236 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1237
1238 return 0;
1239}
1240
1241/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001242int
paul718e3742002-12-13 20:15:29 +00001243bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1244 struct bgp_nlri *mp_update)
1245{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001246 afi_t afi;
1247 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001248 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001249 size_t start;
paul718e3742002-12-13 20:15:29 +00001250 int ret;
1251 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001252 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001253
1254 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001255 s = BGP_INPUT(peer);
1256 start = stream_get_getp(s);
1257
1258 /* safe to read statically sized header? */
1259#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001260#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001261 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001262 {
1263 zlog_info ("%s: %s sent invalid length, %lu",
1264 __func__, peer->host, (unsigned long)length);
1265 return -1;
1266 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001267
paul718e3742002-12-13 20:15:29 +00001268 /* Load AFI, SAFI. */
1269 afi = stream_getw (s);
1270 safi = stream_getc (s);
1271
1272 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001273 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001274
Paul Jakma03292802008-06-07 20:37:10 +00001275 if (LEN_LEFT < attre->mp_nexthop_len)
1276 {
1277 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1278 __func__, peer->host, attre->mp_nexthop_len);
1279 return -1;
1280 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001281
paul718e3742002-12-13 20:15:29 +00001282 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001283 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001284 {
1285 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001286 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001287 /* Probably needed for RFC 2283 */
1288 if (attr->nexthop.s_addr == 0)
1289 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001290 break;
1291 case 12:
1292 {
1293 u_int32_t rd_high;
1294 u_int32_t rd_low;
1295
1296 rd_high = stream_getl (s);
1297 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001298 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001299 }
1300 break;
1301#ifdef HAVE_IPV6
1302 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001303 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001304 break;
1305 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001306 stream_get (&attre->mp_nexthop_global, s, 16);
1307 stream_get (&attre->mp_nexthop_local, s, 16);
1308 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001309 {
1310 char buf1[INET6_ADDRSTRLEN];
1311 char buf2[INET6_ADDRSTRLEN];
1312
1313 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001314 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 +00001315 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001316 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001317 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001318 buf2, INET6_ADDRSTRLEN));
1319
Paul Jakmafb982c22007-05-04 20:15:47 +00001320 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001321 }
1322 break;
1323#endif /* HAVE_IPV6 */
1324 default:
Paul Jakma03292802008-06-07 20:37:10 +00001325 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1326 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001327 return -1;
paul718e3742002-12-13 20:15:29 +00001328 }
1329
Paul Jakma03292802008-06-07 20:37:10 +00001330 if (!LEN_LEFT)
1331 {
1332 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1333 __func__, peer->host);
1334 return -1;
1335 }
paul718e3742002-12-13 20:15:29 +00001336
Paul Jakma6e4ab122007-04-10 19:36:48 +00001337 {
1338 u_char val;
1339 if ((val = stream_getc (s)))
1340 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1341 peer->host, val);
1342 }
1343
1344 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001345 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001346 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001347 {
1348 zlog_info ("%s: (%s) Failed to read NLRI",
1349 __func__, peer->host);
1350 return -1;
1351 }
paul718e3742002-12-13 20:15:29 +00001352
1353 if (safi != BGP_SAFI_VPNV4)
1354 {
1355 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001356 if (ret < 0)
1357 {
1358 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1359 __func__, peer->host);
1360 return -1;
1361 }
paul718e3742002-12-13 20:15:29 +00001362 }
1363
1364 mp_update->afi = afi;
1365 mp_update->safi = safi;
1366 mp_update->nlri = stream_pnt (s);
1367 mp_update->length = nlri_len;
1368
paul9985f832005-02-09 15:51:56 +00001369 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001370
1371 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001372#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001373}
1374
1375/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001376int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001377bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001378 struct bgp_nlri *mp_withdraw)
1379{
1380 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001381 afi_t afi;
1382 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001383 u_int16_t withdraw_len;
1384 int ret;
1385
1386 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001387
1388#define BGP_MP_UNREACH_MIN_SIZE 3
1389 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1390 return -1;
1391
paul718e3742002-12-13 20:15:29 +00001392 afi = stream_getw (s);
1393 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001394
1395 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001396
1397 if (safi != BGP_SAFI_VPNV4)
1398 {
1399 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1400 if (ret < 0)
1401 return -1;
1402 }
1403
1404 mp_withdraw->afi = afi;
1405 mp_withdraw->safi = safi;
1406 mp_withdraw->nlri = stream_pnt (s);
1407 mp_withdraw->length = withdraw_len;
1408
paul9985f832005-02-09 15:51:56 +00001409 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001410
1411 return 0;
1412}
1413
1414/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001415static int
paul718e3742002-12-13 20:15:29 +00001416bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1417 struct attr *attr, u_char flag)
1418{
1419 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001420 {
1421 if (attr->extra)
1422 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001423 /* Empty extcomm doesn't seem to be invalid per se */
1424 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001425 }
Paul Jakma0c466382010-12-05 17:17:26 +00001426
1427 (bgp_attr_extra_get (attr))->ecommunity =
1428 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1429 /* XXX: fix ecommunity_parse to use stream API */
1430 stream_forward_getp (peer->ibuf, length);
1431
1432 if (!attr->extra->ecommunity)
1433 return -1;
1434
paul718e3742002-12-13 20:15:29 +00001435 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1436
1437 return 0;
1438}
1439
1440/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001441static int
paul718e3742002-12-13 20:15:29 +00001442bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1443 u_char type, bgp_size_t length, u_char *startp)
1444{
1445 bgp_size_t total;
1446 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001447 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001448
hassof4184462005-02-01 20:13:16 +00001449 if (BGP_DEBUG (normal, NORMAL))
1450 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1451 peer->host, type, length);
1452
paul718e3742002-12-13 20:15:29 +00001453 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001454 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001455 "Unknown attribute type %d length %d is received", type, length);
1456
1457 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001458 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001459
1460 /* Adjest total length to include type and length. */
1461 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1462
1463 /* If any of the mandatory well-known attributes are not recognized,
1464 then the Error Subcode is set to Unrecognized Well-known
1465 Attribute. The Data field contains the unrecognized attribute
1466 (type, length and value). */
1467 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1468 {
1469 /* Adjust startp to do not include flag value. */
1470 bgp_notify_send_with_data (peer,
1471 BGP_NOTIFY_UPDATE_ERR,
1472 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1473 startp, total);
1474 return -1;
1475 }
1476
1477 /* Unrecognized non-transitive optional attributes must be quietly
1478 ignored and not passed along to other BGP peers. */
1479 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1480 return 0;
1481
1482 /* If a path with recognized transitive optional attribute is
1483 accepted and passed along to other BGP peers and the Partial bit
1484 in the Attribute Flags octet is set to 1 by some previous AS, it
1485 is not set back to 0 by the current AS. */
1486 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1487
1488 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001489 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001490 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001491
Paul Jakmafb982c22007-05-04 20:15:47 +00001492 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001493
1494 if (transit->val)
1495 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1496 transit->length + total);
1497 else
1498 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1499
1500 memcpy (transit->val + transit->length, startp, total);
1501 transit->length += total;
1502
1503 return 0;
1504}
1505
1506/* Read attribute of update packet. This function is called from
1507 bgp_update() in bgpd.c. */
1508int
1509bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1510 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1511{
1512 int ret;
1513 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001514 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001515 bgp_size_t length;
1516 u_char *startp, *endp;
1517 u_char *attr_endp;
1518 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001519 /* we need the as4_path only until we have synthesized the as_path with it */
1520 /* same goes for as4_aggregator */
1521 struct aspath *as4_path = NULL;
1522 as_t as4_aggregator = 0;
1523 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001524
1525 /* Initialize bitmap. */
1526 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1527
1528 /* End pointer of BGP attribute. */
1529 endp = BGP_INPUT_PNT (peer) + size;
1530
1531 /* Get attributes to the end of attribute length. */
1532 while (BGP_INPUT_PNT (peer) < endp)
1533 {
1534 /* Check remaining length check.*/
1535 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1536 {
gdtc29fdba2004-12-09 14:46:46 +00001537 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001538 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001539 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001540 peer->host,
1541 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001542
1543 bgp_notify_send (peer,
1544 BGP_NOTIFY_UPDATE_ERR,
1545 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1546 return -1;
1547 }
1548
1549 /* Fetch attribute flag and type. */
1550 startp = BGP_INPUT_PNT (peer);
1551 flag = stream_getc (BGP_INPUT (peer));
1552 type = stream_getc (BGP_INPUT (peer));
1553
Paul Jakma370b64a2007-12-22 16:49:52 +00001554 /* Check whether Extended-Length applies and is in bounds */
1555 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1556 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1557 {
1558 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001559 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001560 peer->host,
1561 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1562
1563 bgp_notify_send (peer,
1564 BGP_NOTIFY_UPDATE_ERR,
1565 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1566 return -1;
1567 }
1568
paul718e3742002-12-13 20:15:29 +00001569 /* Check extended attribue length bit. */
1570 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1571 length = stream_getw (BGP_INPUT (peer));
1572 else
1573 length = stream_getc (BGP_INPUT (peer));
1574
1575 /* If any attribute appears more than once in the UPDATE
1576 message, then the Error Subcode is set to Malformed Attribute
1577 List. */
1578
1579 if (CHECK_BITMAP (seen, type))
1580 {
1581 zlog (peer->log, LOG_WARNING,
1582 "%s error BGP attribute type %d appears twice in a message",
1583 peer->host, type);
1584
1585 bgp_notify_send (peer,
1586 BGP_NOTIFY_UPDATE_ERR,
1587 BGP_NOTIFY_UPDATE_MAL_ATTR);
1588 return -1;
1589 }
1590
1591 /* Set type to bitmap to check duplicate attribute. `type' is
1592 unsigned char so it never overflow bitmap range. */
1593
1594 SET_BITMAP (seen, type);
1595
1596 /* Overflow check. */
1597 attr_endp = BGP_INPUT_PNT (peer) + length;
1598
1599 if (attr_endp > endp)
1600 {
1601 zlog (peer->log, LOG_WARNING,
1602 "%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);
1603 bgp_notify_send (peer,
1604 BGP_NOTIFY_UPDATE_ERR,
1605 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1606 return -1;
1607 }
1608
1609 /* OK check attribute and store it's value. */
1610 switch (type)
1611 {
1612 case BGP_ATTR_ORIGIN:
1613 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1614 break;
1615 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001616 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1617 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001618 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001619 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001620 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1621 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001622 break;
paul718e3742002-12-13 20:15:29 +00001623 case BGP_ATTR_NEXT_HOP:
1624 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1625 break;
1626 case BGP_ATTR_MULTI_EXIT_DISC:
1627 ret = bgp_attr_med (peer, length, attr, flag, startp);
1628 break;
1629 case BGP_ATTR_LOCAL_PREF:
1630 ret = bgp_attr_local_pref (peer, length, attr, flag);
1631 break;
1632 case BGP_ATTR_ATOMIC_AGGREGATE:
1633 ret = bgp_attr_atomic (peer, length, attr, flag);
1634 break;
1635 case BGP_ATTR_AGGREGATOR:
1636 ret = bgp_attr_aggregator (peer, length, attr, flag);
1637 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001638 case BGP_ATTR_AS4_AGGREGATOR:
1639 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1640 break;
paul718e3742002-12-13 20:15:29 +00001641 case BGP_ATTR_COMMUNITIES:
1642 ret = bgp_attr_community (peer, length, attr, flag);
1643 break;
1644 case BGP_ATTR_ORIGINATOR_ID:
1645 ret = bgp_attr_originator_id (peer, length, attr, flag);
1646 break;
1647 case BGP_ATTR_CLUSTER_LIST:
1648 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1649 break;
1650 case BGP_ATTR_MP_REACH_NLRI:
1651 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1652 break;
1653 case BGP_ATTR_MP_UNREACH_NLRI:
1654 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1655 break;
1656 case BGP_ATTR_EXT_COMMUNITIES:
1657 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1658 break;
1659 default:
1660 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1661 break;
1662 }
1663
1664 /* If error occured immediately return to the caller. */
1665 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001666 {
1667 zlog (peer->log, LOG_WARNING,
1668 "%s: Attribute %s, parse error",
1669 peer->host,
1670 LOOKUP (attr_str, type));
1671 bgp_notify_send (peer,
1672 BGP_NOTIFY_UPDATE_ERR,
1673 BGP_NOTIFY_UPDATE_MAL_ATTR);
1674 return ret;
1675 }
paul718e3742002-12-13 20:15:29 +00001676
1677 /* Check the fetched length. */
1678 if (BGP_INPUT_PNT (peer) != attr_endp)
1679 {
1680 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001681 "%s: BGP attribute %s, fetch error",
1682 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001683 bgp_notify_send (peer,
1684 BGP_NOTIFY_UPDATE_ERR,
1685 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1686 return -1;
1687 }
1688 }
1689
1690 /* Check final read pointer is same as end pointer. */
1691 if (BGP_INPUT_PNT (peer) != endp)
1692 {
1693 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001694 "%s BGP attribute %s, length mismatch",
1695 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001696 bgp_notify_send (peer,
1697 BGP_NOTIFY_UPDATE_ERR,
1698 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1699 return -1;
1700 }
1701
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001702 /*
1703 * At this place we can see whether we got AS4_PATH and/or
1704 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1705 * We can not do this before we've read all attributes because
1706 * the as4 handling does not say whether AS4_PATH has to be sent
1707 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1708 * in relationship to AGGREGATOR.
1709 * So, to be defensive, we are not relying on any order and read
1710 * all attributes first, including these 32bit ones, and now,
1711 * afterwards, we look what and if something is to be done for as4.
1712 */
1713 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1714 as4_aggregator, &as4_aggregator_addr))
1715 return -1;
1716
1717 /* At this stage, we have done all fiddling with as4, and the
1718 * resulting info is in attr->aggregator resp. attr->aspath
1719 * so we can chuck as4_aggregator and as4_path alltogether in
1720 * order to save memory
1721 */
1722 if ( as4_path )
1723 {
1724 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1725 as4_path = NULL;
1726 /* The flag that we got this is still there, but that does not
1727 * do any trouble
1728 */
1729 }
1730 /*
1731 * The "rest" of the code does nothing with as4_aggregator.
1732 * there is no memory attached specifically which is not part
1733 * of the attr.
1734 * so ignoring just means do nothing.
1735 */
1736 /*
1737 * Finally do the checks on the aspath we did not do yet
1738 * because we waited for a potentially synthesized aspath.
1739 */
1740 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1741 {
1742 ret = bgp_attr_aspath_check( peer, attr );
1743 if ( ret < 0 )
1744 return ret;
1745 }
1746
paul718e3742002-12-13 20:15:29 +00001747 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001748 if (attr->extra && attr->extra->transit)
1749 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001750
1751 return 0;
1752}
1753
1754/* Well-known attribute check. */
1755int
1756bgp_attr_check (struct peer *peer, struct attr *attr)
1757{
1758 u_char type = 0;
1759
1760 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1761 type = BGP_ATTR_ORIGIN;
1762
1763 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1764 type = BGP_ATTR_AS_PATH;
1765
1766 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1767 type = BGP_ATTR_NEXT_HOP;
1768
1769 if (peer_sort (peer) == BGP_PEER_IBGP
1770 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1771 type = BGP_ATTR_LOCAL_PREF;
1772
1773 if (type)
1774 {
1775 zlog (peer->log, LOG_WARNING,
1776 "%s Missing well-known attribute %d.",
1777 peer->host, type);
1778 bgp_notify_send_with_data (peer,
1779 BGP_NOTIFY_UPDATE_ERR,
1780 BGP_NOTIFY_UPDATE_MISS_ATTR,
1781 &type, 1);
1782 return -1;
1783 }
1784 return 0;
1785}
1786
1787int stream_put_prefix (struct stream *, struct prefix *);
1788
1789/* Make attribute packet. */
1790bgp_size_t
1791bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1792 struct stream *s, struct attr *attr, struct prefix *p,
1793 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001794 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001795{
paulfe69a502005-09-10 16:55:02 +00001796 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001797 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001798 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001799 int send_as4_path = 0;
1800 int send_as4_aggregator = 0;
1801 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001802
1803 if (! bgp)
1804 bgp = bgp_get_default ();
1805
1806 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001807 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001808
1809 /* Origin attribute. */
1810 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1811 stream_putc (s, BGP_ATTR_ORIGIN);
1812 stream_putc (s, 1);
1813 stream_putc (s, attr->origin);
1814
1815 /* AS path attribute. */
1816
1817 /* If remote-peer is EBGP */
1818 if (peer_sort (peer) == BGP_PEER_EBGP
1819 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001820 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001821 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001822 {
1823 aspath = aspath_dup (attr->aspath);
1824
1825 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1826 {
1827 /* Strip the confed info, and then stuff our path CONFED_ID
1828 on the front */
1829 aspath = aspath_delete_confed_seq (aspath);
1830 aspath = aspath_add_seq (aspath, bgp->confed_id);
1831 }
1832 else
1833 {
1834 aspath = aspath_add_seq (aspath, peer->local_as);
1835 if (peer->change_local_as)
1836 aspath = aspath_add_seq (aspath, peer->change_local_as);
1837 }
1838 }
1839 else if (peer_sort (peer) == BGP_PEER_CONFED)
1840 {
1841 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1842 aspath = aspath_dup (attr->aspath);
1843 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1844 }
1845 else
1846 aspath = attr->aspath;
1847
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001848 /* If peer is not AS4 capable, then:
1849 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1850 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1851 * types are in it (i.e. exclude them if they are there)
1852 * AND do this only if there is at least one asnum > 65535 in the path!
1853 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1854 * all ASnums > 65535 to BGP_AS_TRANS
1855 */
paul718e3742002-12-13 20:15:29 +00001856
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001857 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1858 stream_putc (s, BGP_ATTR_AS_PATH);
1859 aspath_sizep = stream_get_endp (s);
1860 stream_putw (s, 0);
1861 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1862
1863 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1864 * in the path
1865 */
1866 if (!use32bit && aspath_has_as4 (aspath))
1867 send_as4_path = 1; /* we'll do this later, at the correct place */
1868
paul718e3742002-12-13 20:15:29 +00001869 /* Nexthop attribute. */
1870 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1871 {
1872 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1873 stream_putc (s, BGP_ATTR_NEXT_HOP);
1874 stream_putc (s, 4);
1875 if (safi == SAFI_MPLS_VPN)
1876 {
1877 if (attr->nexthop.s_addr == 0)
1878 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1879 else
1880 stream_put_ipv4 (s, attr->nexthop.s_addr);
1881 }
1882 else
1883 stream_put_ipv4 (s, attr->nexthop.s_addr);
1884 }
1885
1886 /* MED attribute. */
1887 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1888 {
1889 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1890 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1891 stream_putc (s, 4);
1892 stream_putl (s, attr->med);
1893 }
1894
1895 /* Local preference. */
1896 if (peer_sort (peer) == BGP_PEER_IBGP ||
1897 peer_sort (peer) == BGP_PEER_CONFED)
1898 {
1899 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1900 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1901 stream_putc (s, 4);
1902 stream_putl (s, attr->local_pref);
1903 }
1904
1905 /* Atomic aggregate. */
1906 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1907 {
1908 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1909 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1910 stream_putc (s, 0);
1911 }
1912
1913 /* Aggregator. */
1914 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1915 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001916 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001917
1918 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001919 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1920 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001921
1922 if (use32bit)
1923 {
1924 /* AS4 capable peer */
1925 stream_putc (s, 8);
1926 stream_putl (s, attr->extra->aggregator_as);
1927 }
1928 else
1929 {
1930 /* 2-byte AS peer */
1931 stream_putc (s, 6);
1932
1933 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1934 if ( attr->extra->aggregator_as > 65535 )
1935 {
1936 stream_putw (s, BGP_AS_TRANS);
1937
1938 /* we have to send AS4_AGGREGATOR, too.
1939 * we'll do that later in order to send attributes in ascending
1940 * order.
1941 */
1942 send_as4_aggregator = 1;
1943 }
1944 else
1945 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1946 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001947 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001948 }
1949
1950 /* Community attribute. */
1951 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1952 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1953 {
1954 if (attr->community->size * 4 > 255)
1955 {
1956 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1957 stream_putc (s, BGP_ATTR_COMMUNITIES);
1958 stream_putw (s, attr->community->size * 4);
1959 }
1960 else
1961 {
1962 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1963 stream_putc (s, BGP_ATTR_COMMUNITIES);
1964 stream_putc (s, attr->community->size * 4);
1965 }
1966 stream_put (s, attr->community->val, attr->community->size * 4);
1967 }
1968
1969 /* Route Reflector. */
1970 if (peer_sort (peer) == BGP_PEER_IBGP
1971 && from
1972 && peer_sort (from) == BGP_PEER_IBGP)
1973 {
1974 /* Originator ID. */
1975 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1976 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1977 stream_putc (s, 4);
1978
1979 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001980 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001981 else
1982 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001983
1984 /* Cluster list. */
1985 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1986 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1987
Paul Jakma9eda90c2007-08-30 13:36:17 +00001988 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001989 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001990 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001991 /* If this peer configuration's parent BGP has cluster_id. */
1992 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1993 stream_put_in_addr (s, &bgp->cluster_id);
1994 else
1995 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001996 stream_put (s, attr->extra->cluster->list,
1997 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001998 }
1999 else
2000 {
2001 stream_putc (s, 4);
2002 /* If this peer configuration's parent BGP has cluster_id. */
2003 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2004 stream_put_in_addr (s, &bgp->cluster_id);
2005 else
2006 stream_put_in_addr (s, &bgp->router_id);
2007 }
2008 }
2009
2010#ifdef HAVE_IPV6
2011 /* If p is IPv6 address put it into attribute. */
2012 if (p->family == AF_INET6)
2013 {
2014 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002015 struct attr_extra *attre = attr->extra;
2016
2017 assert (attr->extra);
2018
paul718e3742002-12-13 20:15:29 +00002019 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2020 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002021 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002022 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002023 stream_putw (s, AFI_IP6); /* AFI */
2024 stream_putc (s, safi); /* SAFI */
2025
Paul Jakmafb982c22007-05-04 20:15:47 +00002026 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002027
Paul Jakmafb982c22007-05-04 20:15:47 +00002028 if (attre->mp_nexthop_len == 16)
2029 stream_put (s, &attre->mp_nexthop_global, 16);
2030 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002031 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002032 stream_put (s, &attre->mp_nexthop_global, 16);
2033 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002034 }
2035
2036 /* SNPA */
2037 stream_putc (s, 0);
2038
paul718e3742002-12-13 20:15:29 +00002039 /* Prefix write. */
2040 stream_put_prefix (s, p);
2041
2042 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002043 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002044 }
2045#endif /* HAVE_IPV6 */
2046
2047 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2048 {
2049 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002050
2051 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2052 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002053 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002054 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002055 stream_putw (s, AFI_IP); /* AFI */
2056 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2057
2058 stream_putc (s, 4);
2059 stream_put_ipv4 (s, attr->nexthop.s_addr);
2060
2061 /* SNPA */
2062 stream_putc (s, 0);
2063
paul718e3742002-12-13 20:15:29 +00002064 /* Prefix write. */
2065 stream_put_prefix (s, p);
2066
2067 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002068 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002069 }
2070
2071 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2072 {
2073 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002074
2075 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2076 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002077 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002078 stream_putc (s, 0); /* Length of this attribute. */
2079 stream_putw (s, AFI_IP); /* AFI */
2080 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2081
2082 stream_putc (s, 12);
2083 stream_putl (s, 0);
2084 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002085 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002086
2087 /* SNPA */
2088 stream_putc (s, 0);
2089
paul718e3742002-12-13 20:15:29 +00002090 /* Tag, RD, Prefix write. */
2091 stream_putc (s, p->prefixlen + 88);
2092 stream_put (s, tag, 3);
2093 stream_put (s, prd->val, 8);
2094 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2095
2096 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002097 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002098 }
2099
2100 /* Extended Communities attribute. */
2101 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2102 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2103 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002104 struct attr_extra *attre = attr->extra;
2105
2106 assert (attre);
2107
2108 if (peer_sort (peer) == BGP_PEER_IBGP
2109 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002110 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002111 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002112 {
2113 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2114 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002115 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002116 }
2117 else
2118 {
2119 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2120 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002121 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002122 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002123 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002124 }
2125 else
2126 {
paul5228ad22004-06-04 17:58:18 +00002127 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002128 int tbit;
2129 int ecom_tr_size = 0;
2130 int i;
2131
Paul Jakmafb982c22007-05-04 20:15:47 +00002132 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002133 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002134 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002135 tbit = *pnt;
2136
2137 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2138 continue;
2139
2140 ecom_tr_size++;
2141 }
2142
2143 if (ecom_tr_size)
2144 {
2145 if (ecom_tr_size * 8 > 255)
2146 {
2147 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2148 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2149 stream_putw (s, ecom_tr_size * 8);
2150 }
2151 else
2152 {
2153 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2154 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2155 stream_putc (s, ecom_tr_size * 8);
2156 }
2157
Paul Jakmafb982c22007-05-04 20:15:47 +00002158 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002159 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002160 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002161 tbit = *pnt;
2162
2163 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2164 continue;
2165
2166 stream_put (s, pnt, 8);
2167 }
2168 }
paul718e3742002-12-13 20:15:29 +00002169 }
paul718e3742002-12-13 20:15:29 +00002170 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002171
2172 if ( send_as4_path )
2173 {
2174 /* If the peer is NOT As4 capable, AND */
2175 /* there are ASnums > 65535 in path THEN
2176 * give out AS4_PATH */
2177
2178 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2179 * path segments!
2180 * Hm, I wonder... confederation things *should* only be at
2181 * the beginning of an aspath, right? Then we should use
2182 * aspath_delete_confed_seq for this, because it is already
2183 * there! (JK)
2184 * Folks, talk to me: what is reasonable here!?
2185 */
2186 aspath = aspath_delete_confed_seq (aspath);
2187
2188 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2189 stream_putc (s, BGP_ATTR_AS4_PATH);
2190 aspath_sizep = stream_get_endp (s);
2191 stream_putw (s, 0);
2192 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2193 }
2194
2195 if (aspath != attr->aspath)
2196 aspath_free (aspath);
2197
2198 if ( send_as4_aggregator )
2199 {
2200 assert (attr->extra);
2201
2202 /* send AS4_AGGREGATOR, at this place */
2203 /* this section of code moved here in order to ensure the correct
2204 * *ascending* order of attributes
2205 */
2206 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2207 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2208 stream_putc (s, 8);
2209 stream_putl (s, attr->extra->aggregator_as);
2210 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2211 }
Paul Jakma41367172007-08-06 15:24:51 +00002212
paul718e3742002-12-13 20:15:29 +00002213 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002214 if (attr->extra && attr->extra->transit)
2215 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002216
2217 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002218 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002219}
2220
2221bgp_size_t
2222bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2223 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002224 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002225{
2226 unsigned long cp;
2227 unsigned long attrlen_pnt;
2228 bgp_size_t size;
2229
paul9985f832005-02-09 15:51:56 +00002230 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002231
2232 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2233 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2234
paul9985f832005-02-09 15:51:56 +00002235 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002236 stream_putc (s, 0); /* Length of this attribute. */
2237
2238 stream_putw (s, family2afi (p->family));
2239
2240 if (safi == SAFI_MPLS_VPN)
2241 {
2242 /* SAFI */
2243 stream_putc (s, BGP_SAFI_VPNV4);
2244
2245 /* prefix. */
2246 stream_putc (s, p->prefixlen + 88);
2247 stream_put (s, tag, 3);
2248 stream_put (s, prd->val, 8);
2249 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2250 }
2251 else
2252 {
2253 /* SAFI */
2254 stream_putc (s, safi);
2255
2256 /* prefix */
2257 stream_put_prefix (s, p);
2258 }
2259
2260 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002261 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002262 stream_putc_at (s, attrlen_pnt, size);
2263
paul9985f832005-02-09 15:51:56 +00002264 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002265}
2266
2267/* Initialization of attribute. */
2268void
paulfe69a502005-09-10 16:55:02 +00002269bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002270{
paul718e3742002-12-13 20:15:29 +00002271 aspath_init ();
2272 attrhash_init ();
2273 community_init ();
2274 ecommunity_init ();
2275 cluster_init ();
2276 transit_init ();
2277}
2278
Chris Caputo228da422009-07-18 05:44:03 +00002279void
2280bgp_attr_finish (void)
2281{
2282 aspath_finish ();
2283 attrhash_finish ();
2284 community_finish ();
2285 ecommunity_finish ();
2286 cluster_finish ();
2287 transit_finish ();
2288}
2289
paul718e3742002-12-13 20:15:29 +00002290/* Make attribute packet. */
2291void
paula3845922003-10-18 01:30:50 +00002292bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2293 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002294{
2295 unsigned long cp;
2296 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002297 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002298 struct aspath *aspath;
2299
2300 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002301 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002302
2303 /* Place holder of length. */
2304 stream_putw (s, 0);
2305
2306 /* Origin attribute. */
2307 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2308 stream_putc (s, BGP_ATTR_ORIGIN);
2309 stream_putc (s, 1);
2310 stream_putc (s, attr->origin);
2311
2312 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002313
2314 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2315 stream_putc (s, BGP_ATTR_AS_PATH);
2316 aspath_lenp = stream_get_endp (s);
2317 stream_putw (s, 0);
2318
2319 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002320
2321 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002322 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2323 if(prefix != NULL
2324#ifdef HAVE_IPV6
2325 && prefix->family != AF_INET6
2326#endif /* HAVE_IPV6 */
2327 )
2328 {
2329 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2330 stream_putc (s, BGP_ATTR_NEXT_HOP);
2331 stream_putc (s, 4);
2332 stream_put_ipv4 (s, attr->nexthop.s_addr);
2333 }
paul718e3742002-12-13 20:15:29 +00002334
2335 /* MED attribute. */
2336 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2337 {
2338 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2339 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2340 stream_putc (s, 4);
2341 stream_putl (s, attr->med);
2342 }
2343
2344 /* Local preference. */
2345 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2346 {
2347 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2348 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2349 stream_putc (s, 4);
2350 stream_putl (s, attr->local_pref);
2351 }
2352
2353 /* Atomic aggregate. */
2354 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2355 {
2356 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2357 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2358 stream_putc (s, 0);
2359 }
2360
2361 /* Aggregator. */
2362 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2363 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002364 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002365 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2366 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002367 stream_putc (s, 8);
2368 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002369 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002370 }
2371
2372 /* Community attribute. */
2373 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2374 {
2375 if (attr->community->size * 4 > 255)
2376 {
2377 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2378 stream_putc (s, BGP_ATTR_COMMUNITIES);
2379 stream_putw (s, attr->community->size * 4);
2380 }
2381 else
2382 {
2383 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2384 stream_putc (s, BGP_ATTR_COMMUNITIES);
2385 stream_putc (s, attr->community->size * 4);
2386 }
2387 stream_put (s, attr->community->val, attr->community->size * 4);
2388 }
2389
paula3845922003-10-18 01:30:50 +00002390#ifdef HAVE_IPV6
2391 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002392 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2393 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002394 {
2395 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002396 struct attr_extra *attre = attr->extra;
2397
paula3845922003-10-18 01:30:50 +00002398 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2399 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002400 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002401
2402 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002403 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002404 stream_putw(s, AFI_IP6); /* AFI */
2405 stream_putc(s, SAFI_UNICAST); /* SAFI */
2406
2407 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002408 stream_putc(s, attre->mp_nexthop_len);
2409 stream_put(s, &attre->mp_nexthop_global, 16);
2410 if (attre->mp_nexthop_len == 32)
2411 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002412
2413 /* SNPA */
2414 stream_putc(s, 0);
2415
2416 /* Prefix */
2417 stream_put_prefix(s, prefix);
2418
2419 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002420 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002421 }
2422#endif /* HAVE_IPV6 */
2423
paul718e3742002-12-13 20:15:29 +00002424 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002425 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002426 stream_putw_at (s, cp, len);
2427}