blob: 337ddb7c54eb6ea6d86b6fc1d3da830d6dd5c42a [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -070031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_route.h"
36#include "bgpd/bgp_aspath.h"
37#include "bgpd/bgp_community.h"
38#include "bgpd/bgp_debug.h"
39#include "bgpd/bgp_packet.h"
40#include "bgpd/bgp_ecommunity.h"
41
42/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070043static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000044{
45 { BGP_ATTR_ORIGIN, "ORIGIN" },
46 { BGP_ATTR_AS_PATH, "AS_PATH" },
47 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
54 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
55 { BGP_ATTR_DPA, "DPA" },
56 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000064};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070065static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000066
Stephen Hemminger9bddac42009-05-15 09:59:51 -070067static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000068
paul94f2b392005-06-28 12:44:16 +000069static void *
Paul Jakma923de652007-04-29 18:25:17 +000070cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000071{
Paul Jakma923de652007-04-29 18:25:17 +000072 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000073 struct cluster_list *cluster;
74
75 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
76 cluster->length = val->length;
77
78 if (cluster->length)
79 {
80 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
81 memcpy (cluster->list, val->list, val->length);
82 }
83 else
84 cluster->list = NULL;
85
86 cluster->refcnt = 0;
87
88 return cluster;
89}
90
91/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000092static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000093cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000094{
95 struct cluster_list tmp;
96 struct cluster_list *cluster;
97
98 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000099 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000100
101 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
102 cluster->refcnt++;
103 return cluster;
104}
105
106int
107cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
108{
109 int i;
110
111 for (i = 0; i < cluster->length / 4; i++)
112 if (cluster->list[i].s_addr == originator.s_addr)
113 return 1;
114 return 0;
115}
116
paul94f2b392005-06-28 12:44:16 +0000117static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000118cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000119{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700120 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000121
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700122 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000123}
124
paul94f2b392005-06-28 12:44:16 +0000125static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100126cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000127{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100128 const struct cluster_list * cluster1 = p1;
129 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000130
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100131 return (cluster1->length == cluster2->length &&
132 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000133}
134
paul94f2b392005-06-28 12:44:16 +0000135static void
paul718e3742002-12-13 20:15:29 +0000136cluster_free (struct cluster_list *cluster)
137{
138 if (cluster->list)
139 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
140 XFREE (MTYPE_CLUSTER, cluster);
141}
142
Chris Caputo228da422009-07-18 05:44:03 +0000143#if 0
paul94f2b392005-06-28 12:44:16 +0000144static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000145cluster_dup (struct cluster_list *cluster)
146{
147 struct cluster_list *new;
148
Stephen Hemminger393deb92008-08-18 14:13:29 -0700149 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000150 new->length = cluster->length;
151
152 if (cluster->length)
153 {
154 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
155 memcpy (new->list, cluster->list, cluster->length);
156 }
157 else
158 new->list = NULL;
159
160 return new;
161}
Chris Caputo228da422009-07-18 05:44:03 +0000162#endif
paul718e3742002-12-13 20:15:29 +0000163
paul94f2b392005-06-28 12:44:16 +0000164static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000165cluster_intern (struct cluster_list *cluster)
166{
167 struct cluster_list *find;
168
169 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
170 find->refcnt++;
171
172 return find;
173}
174
175void
176cluster_unintern (struct cluster_list *cluster)
177{
178 struct cluster_list *ret;
179
180 if (cluster->refcnt)
181 cluster->refcnt--;
182
183 if (cluster->refcnt == 0)
184 {
185 ret = hash_release (cluster_hash, cluster);
186 cluster_free (cluster);
187 }
188}
189
paul94f2b392005-06-28 12:44:16 +0000190static void
191cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000192{
193 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
194}
Chris Caputo228da422009-07-18 05:44:03 +0000195
196static void
197cluster_finish (void)
198{
199 hash_free (cluster_hash);
200 cluster_hash = NULL;
201}
paul718e3742002-12-13 20:15:29 +0000202
203/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700204static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000205
paul94f2b392005-06-28 12:44:16 +0000206static void
paul718e3742002-12-13 20:15:29 +0000207transit_free (struct transit *transit)
208{
209 if (transit->val)
210 XFREE (MTYPE_TRANSIT_VAL, transit->val);
211 XFREE (MTYPE_TRANSIT, transit);
212}
213
Paul Jakma923de652007-04-29 18:25:17 +0000214
paul94f2b392005-06-28 12:44:16 +0000215static void *
Paul Jakma923de652007-04-29 18:25:17 +0000216transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000217{
218 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000219 return p;
paul718e3742002-12-13 20:15:29 +0000220}
221
paul94f2b392005-06-28 12:44:16 +0000222static struct transit *
paul718e3742002-12-13 20:15:29 +0000223transit_intern (struct transit *transit)
224{
225 struct transit *find;
226
227 find = hash_get (transit_hash, transit, transit_hash_alloc);
228 if (find != transit)
229 transit_free (transit);
230 find->refcnt++;
231
232 return find;
233}
234
235void
236transit_unintern (struct transit *transit)
237{
238 struct transit *ret;
239
240 if (transit->refcnt)
241 transit->refcnt--;
242
243 if (transit->refcnt == 0)
244 {
245 ret = hash_release (transit_hash, transit);
246 transit_free (transit);
247 }
248}
249
paul94f2b392005-06-28 12:44:16 +0000250static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000251transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000252{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700253 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000254
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700255 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000256}
257
paul94f2b392005-06-28 12:44:16 +0000258static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100259transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000260{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100261 const struct transit * transit1 = p1;
262 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000263
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100264 return (transit1->length == transit2->length &&
265 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000266}
267
paul94f2b392005-06-28 12:44:16 +0000268static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800269transit_init (void)
paul718e3742002-12-13 20:15:29 +0000270{
271 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
272}
Chris Caputo228da422009-07-18 05:44:03 +0000273
274static void
275transit_finish (void)
276{
277 hash_free (transit_hash);
278 transit_hash = NULL;
279}
paul718e3742002-12-13 20:15:29 +0000280
281/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700282static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000283
Paul Jakmafb982c22007-05-04 20:15:47 +0000284static struct attr_extra *
285bgp_attr_extra_new (void)
286{
287 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
288}
289
290void
291bgp_attr_extra_free (struct attr *attr)
292{
293 if (attr->extra)
294 {
295 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
296 attr->extra = NULL;
297 }
298}
299
300struct attr_extra *
301bgp_attr_extra_get (struct attr *attr)
302{
303 if (!attr->extra)
304 attr->extra = bgp_attr_extra_new();
305 return attr->extra;
306}
307
308/* Shallow copy of an attribute
309 * Though, not so shallow that it doesn't copy the contents
310 * of the attr_extra pointed to by 'extra'
311 */
312void
313bgp_attr_dup (struct attr *new, struct attr *orig)
314{
315 *new = *orig;
316 if (orig->extra)
317 {
318 new->extra = bgp_attr_extra_new();
319 *new->extra = *orig->extra;
320 }
321}
322
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000323unsigned long int
324attr_count (void)
325{
326 return attrhash->count;
327}
328
329unsigned long int
330attr_unknown_count (void)
331{
332 return transit_hash->count;
333}
334
paul718e3742002-12-13 20:15:29 +0000335unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000336attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000337{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700338 const struct attr * attr = (struct attr *) p;
339 uint32_t key = 0;
340#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000341
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700342 MIX(attr->origin);
343 MIX(attr->nexthop.s_addr);
344 MIX(attr->med);
345 MIX(attr->local_pref);
346
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000347 key += attr->origin;
348 key += attr->nexthop.s_addr;
349 key += attr->med;
350 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000351
352 if (attr->extra)
353 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700354 MIX(attr->extra->aggregator_as);
355 MIX(attr->extra->aggregator_addr.s_addr);
356 MIX(attr->extra->weight);
357 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000358 }
359
paul718e3742002-12-13 20:15:29 +0000360 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700361 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000362 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700363 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000364
365 if (attr->extra)
366 {
367 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700368 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000369 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700370 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000371 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700372 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000373
374#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700375 MIX(attr->extra->mp_nexthop_len);
Paul Jakma31d0f1b2011-03-29 14:18:49 +0100376 key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
377 key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000378#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000379 }
paul718e3742002-12-13 20:15:29 +0000380
381 return key;
382}
383
384int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100385attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000386{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100387 const struct attr * attr1 = p1;
388 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000389
paul718e3742002-12-13 20:15:29 +0000390 if (attr1->flag == attr2->flag
391 && attr1->origin == attr2->origin
392 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000393 && attr1->aspath == attr2->aspath
394 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000395 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000396 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000397 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100398 const struct attr_extra *ae1 = attr1->extra;
399 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000400
401 if (ae1 && ae2
402 && ae1->aggregator_as == ae2->aggregator_as
403 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
404 && ae1->weight == ae2->weight
405#ifdef HAVE_IPV6
406 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
407 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
408 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
409#endif /* HAVE_IPV6 */
410 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
411 && ae1->ecommunity == ae2->ecommunity
412 && ae1->cluster == ae2->cluster
413 && ae1->transit == ae2->transit)
414 return 1;
415 else if (ae1 || ae2)
416 return 0;
417 /* neither attribute has extra attributes, so they're same */
418 return 1;
419 }
paul718e3742002-12-13 20:15:29 +0000420 else
421 return 0;
422}
423
paul94f2b392005-06-28 12:44:16 +0000424static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100425attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000426{
427 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
428}
429
paul94f2b392005-06-28 12:44:16 +0000430static void
Chris Caputo228da422009-07-18 05:44:03 +0000431attrhash_finish (void)
432{
433 hash_free (attrhash);
434 attrhash = NULL;
435}
436
437static void
paul718e3742002-12-13 20:15:29 +0000438attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
439{
440 struct attr *attr = backet->data;
441
442 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
443 inet_ntoa (attr->nexthop), VTY_NEWLINE);
444}
445
446void
447attr_show_all (struct vty *vty)
448{
449 hash_iterate (attrhash,
450 (void (*)(struct hash_backet *, void *))
451 attr_show_all_iterator,
452 vty);
453}
454
paul94f2b392005-06-28 12:44:16 +0000455static void *
Paul Jakma923de652007-04-29 18:25:17 +0000456bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000457{
Paul Jakma923de652007-04-29 18:25:17 +0000458 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000459 struct attr *attr;
460
461 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
462 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000463 if (val->extra)
464 {
465 attr->extra = bgp_attr_extra_new ();
466 *attr->extra = *val->extra;
467 }
paul718e3742002-12-13 20:15:29 +0000468 attr->refcnt = 0;
469 return attr;
470}
471
472/* Internet argument attribute. */
473struct attr *
474bgp_attr_intern (struct attr *attr)
475{
476 struct attr *find;
477
478 /* Intern referenced strucutre. */
479 if (attr->aspath)
480 {
481 if (! attr->aspath->refcnt)
482 attr->aspath = aspath_intern (attr->aspath);
483 else
484 attr->aspath->refcnt++;
485 }
486 if (attr->community)
487 {
488 if (! attr->community->refcnt)
489 attr->community = community_intern (attr->community);
490 else
491 attr->community->refcnt++;
492 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000493 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000494 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000495 struct attr_extra *attre = attr->extra;
496
497 if (attre->ecommunity)
498 {
499 if (! attre->ecommunity->refcnt)
500 attre->ecommunity = ecommunity_intern (attre->ecommunity);
501 else
502 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000503
Paul Jakmafb982c22007-05-04 20:15:47 +0000504 }
505 if (attre->cluster)
506 {
507 if (! attre->cluster->refcnt)
508 attre->cluster = cluster_intern (attre->cluster);
509 else
510 attre->cluster->refcnt++;
511 }
512 if (attre->transit)
513 {
514 if (! attre->transit->refcnt)
515 attre->transit = transit_intern (attre->transit);
516 else
517 attre->transit->refcnt++;
518 }
paul718e3742002-12-13 20:15:29 +0000519 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000520
paul718e3742002-12-13 20:15:29 +0000521 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
522 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000523
paul718e3742002-12-13 20:15:29 +0000524 return find;
525}
526
Paul Jakma03e214c2007-04-29 18:31:07 +0000527
paul718e3742002-12-13 20:15:29 +0000528/* Make network statement's attribute. */
529struct attr *
530bgp_attr_default_set (struct attr *attr, u_char origin)
531{
532 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000533 bgp_attr_extra_get (attr);
534
paul718e3742002-12-13 20:15:29 +0000535 attr->origin = origin;
536 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
537 attr->aspath = aspath_empty ();
538 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000539 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000540 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
541#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000542 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000543#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000544
paul718e3742002-12-13 20:15:29 +0000545 return attr;
546}
547
Paul Jakma03e214c2007-04-29 18:31:07 +0000548
paul718e3742002-12-13 20:15:29 +0000549/* Make network statement's attribute. */
550struct attr *
551bgp_attr_default_intern (u_char origin)
552{
553 struct attr attr;
554 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 struct attr_extra *attre;
556
557 memset (&attr, 0, sizeof (struct attr));
558 attre = bgp_attr_extra_get (&attr);
559
Paul Jakma03e214c2007-04-29 18:31:07 +0000560 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000561
562 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000563 bgp_attr_extra_free (&attr);
564
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000565 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000566 return new;
567}
568
569struct attr *
570bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
571 struct aspath *aspath,
572 struct community *community, int as_set)
573{
574 struct attr attr;
575 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000576 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000577
578 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 attre = bgp_attr_extra_get (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 /* Origin attribute. */
582 attr.origin = origin;
583 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
584
585 /* AS path attribute. */
586 if (aspath)
587 attr.aspath = aspath_intern (aspath);
588 else
589 attr.aspath = aspath_empty ();
590 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
591
592 /* Next hop attribute. */
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
594
595 if (community)
596 {
597 attr.community = community;
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
599 }
600
Paul Jakmafb982c22007-05-04 20:15:47 +0000601 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000602#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000603 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000604#endif
605 if (! as_set)
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
608 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000609 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000610 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000611 attre->aggregator_as = bgp->as;
612 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000613
614 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 bgp_attr_extra_free (&attr);
616
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000617 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000618 return new;
619}
620
Paul Jakmab881c702010-11-23 16:35:42 +0000621/* Unintern just the sub-components of the attr, but not the attr */
622void
623bgp_attr_unintern_sub (struct attr *attr)
624{
625 /* aspath refcount shoud be decrement. */
626 if (attr->aspath)
627 aspath_unintern (&attr->aspath);
628 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
629
630 if (attr->community)
631 community_unintern (&attr->community);
632 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
633
634 if (attr->extra)
635 {
636 if (attr->extra->ecommunity)
637 ecommunity_unintern (&attr->extra->ecommunity);
638 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
639
640 if (attr->extra->cluster)
641 cluster_unintern (attr->extra->cluster);
642 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
643
644 if (attr->extra->transit)
645 transit_unintern (attr->extra->transit);
646 }
647}
648
paul718e3742002-12-13 20:15:29 +0000649/* Free bgp attribute and aspath. */
650void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000651bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000652{
653 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000654 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000655
paul718e3742002-12-13 20:15:29 +0000656 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000657 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000658
659 tmp = *(*attr);
660
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000662 {
Paul Jakmab881c702010-11-23 16:35:42 +0000663 tmp.extra = bgp_attr_extra_new ();
664 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000665 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000666
paul718e3742002-12-13 20:15:29 +0000667 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000668 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000669 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000670 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000671 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672 bgp_attr_extra_free (*attr);
673 XFREE (MTYPE_ATTR, *attr);
674 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000675 }
676
Paul Jakmab881c702010-11-23 16:35:42 +0000677 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000678}
679
680void
681bgp_attr_flush (struct attr *attr)
682{
683 if (attr->aspath && ! attr->aspath->refcnt)
684 aspath_free (attr->aspath);
685 if (attr->community && ! attr->community->refcnt)
686 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000687 if (attr->extra)
688 {
689 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000690
Paul Jakmafb982c22007-05-04 20:15:47 +0000691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000692 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000693 if (attre->cluster && ! attre->cluster->refcnt)
694 cluster_free (attre->cluster);
695 if (attre->transit && ! attre->transit->refcnt)
696 transit_free (attre->transit);
697 }
paul718e3742002-12-13 20:15:29 +0000698}
699
Paul Jakmab881c702010-11-23 16:35:42 +0000700/* Implement draft-scudder-idr-optional-transitive behaviour and
701 * avoid resetting sessions for malformed attributes which are
702 * are partial/optional and hence where the error likely was not
703 * introduced by the sending neighbour.
704 */
705static bgp_attr_parse_ret_t
706bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
707 u_char subcode, u_char *startp, bgp_size_t length)
708{
709 /* Only relax error handling for eBGP peers */
710 if (peer_sort (peer) != BGP_PEER_EBGP)
711 {
712 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
713 startp, length);
714 return BGP_ATTR_PARSE_ERROR;
715
716 }
717
718 switch (type) {
719 /* where an optional attribute is inconsequential, e.g. it does not affect
720 * route selection, and can be safely ignored then any such attributes
721 * which are malformed should just be ignored and the route processed as
722 * normal.
723 */
724 case BGP_ATTR_AS4_AGGREGATOR:
725 case BGP_ATTR_AGGREGATOR:
726 case BGP_ATTR_ATOMIC_AGGREGATE:
727 return BGP_ATTR_PARSE_PROCEED;
728
729 /* Core attributes, particularly ones which may influence route
730 * selection should always cause session resets
731 */
732 case BGP_ATTR_ORIGIN:
733 case BGP_ATTR_AS_PATH:
734 case BGP_ATTR_NEXT_HOP:
735 case BGP_ATTR_MULTI_EXIT_DISC:
736 case BGP_ATTR_LOCAL_PREF:
737 case BGP_ATTR_COMMUNITIES:
738 case BGP_ATTR_ORIGINATOR_ID:
739 case BGP_ATTR_CLUSTER_LIST:
740 case BGP_ATTR_MP_REACH_NLRI:
741 case BGP_ATTR_MP_UNREACH_NLRI:
742 case BGP_ATTR_EXT_COMMUNITIES:
743 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
744 startp, length);
745 return BGP_ATTR_PARSE_ERROR;
746 }
747
748 /* Partial optional attributes that are malformed should not cause
749 * the whole session to be reset. Instead treat it as a withdrawal
750 * of the routes, if possible.
751 */
752 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
753 && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
754 && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
755 return BGP_ATTR_PARSE_WITHDRAW;
756
757 /* default to reset */
758 return BGP_ATTR_PARSE_ERROR;
759}
760
paul718e3742002-12-13 20:15:29 +0000761/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000762static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000763bgp_attr_origin (struct peer *peer, bgp_size_t length,
764 struct attr *attr, u_char flag, u_char *startp)
765{
766 bgp_size_t total;
767
768 /* total is entire attribute length include Attribute Flags (1),
769 Attribute Type code (1) and Attribute length (1 or 2). */
770 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
771
772 /* If any recognized attribute has Attribute Flags that conflict
773 with the Attribute Type Code, then the Error Subcode is set to
774 Attribute Flags Error. The Data field contains the erroneous
775 attribute (type, length and value). */
776 if (flag != BGP_ATTR_FLAG_TRANS)
777 {
778 zlog (peer->log, LOG_ERR,
779 "Origin attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000780 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
781 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
782 startp, total);
paul718e3742002-12-13 20:15:29 +0000783 }
784
785 /* If any recognized attribute has Attribute Length that conflicts
786 with the expected length (based on the attribute type code), then
787 the Error Subcode is set to Attribute Length Error. The Data
788 field contains the erroneous attribute (type, length and
789 value). */
790 if (length != 1)
791 {
792 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
793 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000794 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
795 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
796 startp, total);
paul718e3742002-12-13 20:15:29 +0000797 }
798
799 /* Fetch origin attribute. */
800 attr->origin = stream_getc (BGP_INPUT (peer));
801
802 /* If the ORIGIN attribute has an undefined value, then the Error
803 Subcode is set to Invalid Origin Attribute. The Data field
804 contains the unrecognized attribute (type, length and value). */
805 if ((attr->origin != BGP_ORIGIN_IGP)
806 && (attr->origin != BGP_ORIGIN_EGP)
807 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
808 {
809 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
810 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000811 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
812 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
813 startp, total);
paul718e3742002-12-13 20:15:29 +0000814 }
815
816 /* Set oring attribute flag. */
817 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
818
819 return 0;
820}
Paul Jakmaab005292010-11-27 22:48:34 +0000821
822/* Parse AS path information. This function is wrapper of
823 aspath_parse. */
824static int
paul718e3742002-12-13 20:15:29 +0000825bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000826 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000827{
Paul Jakmaab005292010-11-27 22:48:34 +0000828 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000829
Paul Jakmaab005292010-11-27 22:48:34 +0000830 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000831
Paul Jakmaab005292010-11-27 22:48:34 +0000832 /* Flag check. */
833 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
834 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000835 {
836 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000837 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000838 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
839 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
840 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400841 }
Paul Jakmaab005292010-11-27 22:48:34 +0000842
843 /*
844 * peer with AS4 => will get 4Byte ASnums
845 * otherwise, will get 16 Bit
846 */
847 attr->aspath = aspath_parse (peer->ibuf, length,
848 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
849
850 /* In case of IBGP, length will be zero. */
851 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000852 {
Paul Jakmab881c702010-11-23 16:35:42 +0000853 zlog (peer->log, LOG_ERR,
854 "Malformed AS path from %s, length is %d",
855 peer->host, length);
856 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
857 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
858 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000859 }
Chris Hallcddb8112010-08-09 22:31:37 +0400860
Paul Jakmaab005292010-11-27 22:48:34 +0000861 /* Set aspath attribute flag. */
862 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000863
Paul Jakmab881c702010-11-23 16:35:42 +0000864 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000865}
866
Paul Jakmab881c702010-11-23 16:35:42 +0000867static bgp_attr_parse_ret_t
868bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000869{
870 /* These checks were part of bgp_attr_aspath, but with
871 * as4 we should to check aspath things when
872 * aspath synthesizing with as4_path has already taken place.
873 * Otherwise we check ASPATH and use the synthesized thing, and that is
874 * not right.
875 * So do the checks later, i.e. here
876 */
877 struct bgp *bgp = peer->bgp;
878 struct aspath *aspath;
879
paul718e3742002-12-13 20:15:29 +0000880 bgp = peer->bgp;
881
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300882 /* Confederation sanity check. */
883 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
884 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
885 {
886 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000887 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
888 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
889 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300890 }
891
paul718e3742002-12-13 20:15:29 +0000892 /* First AS check for EBGP. */
893 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
894 {
895 if (peer_sort (peer) == BGP_PEER_EBGP
896 && ! aspath_firstas_check (attr->aspath, peer->as))
897 {
898 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400899 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000900 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
901 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
902 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000903 }
904 }
905
906 /* local-as prepend */
907 if (peer->change_local_as &&
908 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
909 {
910 aspath = aspath_dup (attr->aspath);
911 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000912 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000913 attr->aspath = aspath_intern (aspath);
914 }
915
Paul Jakmab881c702010-11-23 16:35:42 +0000916 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000917}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000918
Paul Jakmaab005292010-11-27 22:48:34 +0000919/* Parse AS4 path information. This function is another wrapper of
920 aspath_parse. */
921static int
Paul Jakmab881c702010-11-23 16:35:42 +0000922bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
923 struct attr *attr, u_char flag, u_char *startp,
924 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000925{
Paul Jakmab881c702010-11-23 16:35:42 +0000926 bgp_size_t total;
927
928 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
929
930 /* Flag check. */
931 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
932 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
933 {
934 zlog (peer->log, LOG_ERR,
935 "As4-Path attribute flag isn't optional/transitive %d", flag);
936 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
937 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
938 startp, total);
939 }
940
Paul Jakmaab005292010-11-27 22:48:34 +0000941 *as4_path = aspath_parse (peer->ibuf, length, 1);
942
Paul Jakmab881c702010-11-23 16:35:42 +0000943 /* In case of IBGP, length will be zero. */
944 if (!*as4_path)
945 {
946 zlog (peer->log, LOG_ERR,
947 "Malformed AS4 path from %s, length is %d",
948 peer->host, length);
949 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
950 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
951 NULL, 0);
952 }
953
Paul Jakmaab005292010-11-27 22:48:34 +0000954 /* Set aspath attribute flag. */
955 if (as4_path)
956 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
957
Paul Jakmab881c702010-11-23 16:35:42 +0000958 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000959}
960
paul718e3742002-12-13 20:15:29 +0000961/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000962static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000963bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
964 struct attr *attr, u_char flag, u_char *startp)
965{
966 bgp_size_t total;
967
968 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
969
970 /* Flag check. */
971 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
972 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
973 {
974 zlog (peer->log, LOG_ERR,
975 "Origin attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000976 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
977 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
978 startp, total);
paul718e3742002-12-13 20:15:29 +0000979 }
980
981 /* Check nexthop attribute length. */
982 if (length != 4)
983 {
984 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
985 length);
986
Paul Jakmab881c702010-11-23 16:35:42 +0000987 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
988 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
989 startp, total);
paul718e3742002-12-13 20:15:29 +0000990 }
991
992 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
993 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
994
Paul Jakmab881c702010-11-23 16:35:42 +0000995 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +0000996}
997
998/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000999static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001000bgp_attr_med (struct peer *peer, bgp_size_t length,
1001 struct attr *attr, u_char flag, u_char *startp)
1002{
1003 bgp_size_t total;
1004
1005 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1006
1007 /* Length check. */
1008 if (length != 4)
1009 {
1010 zlog (peer->log, LOG_ERR,
1011 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001012
1013 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1014 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1015 startp, total);
paul718e3742002-12-13 20:15:29 +00001016 }
1017
1018 attr->med = stream_getl (peer->ibuf);
1019
1020 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1021
Paul Jakmab881c702010-11-23 16:35:42 +00001022 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001023}
1024
1025/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001026static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001027bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001028 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001029{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001030 bgp_size_t total;
1031
1032 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1033 /* Flag checks. */
1034 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1035 {
1036 zlog (peer->log, LOG_ERR,
1037 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1038 bgp_notify_send_with_data (peer,
1039 BGP_NOTIFY_UPDATE_ERR,
1040 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1041 startp, total);
1042 return -1;
1043 }
1044 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1045 {
1046 zlog (peer->log, LOG_ERR,
1047 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1048 bgp_notify_send_with_data (peer,
1049 BGP_NOTIFY_UPDATE_ERR,
1050 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1051 startp, total);
1052 return -1;
1053 }
1054
paul718e3742002-12-13 20:15:29 +00001055 /* If it is contained in an UPDATE message that is received from an
1056 external peer, then this attribute MUST be ignored by the
1057 receiving speaker. */
1058 if (peer_sort (peer) == BGP_PEER_EBGP)
1059 {
paul9985f832005-02-09 15:51:56 +00001060 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001061 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001062 }
1063
1064 if (length == 4)
1065 attr->local_pref = stream_getl (peer->ibuf);
1066 else
1067 attr->local_pref = 0;
1068
1069 /* Set atomic aggregate flag. */
1070 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1071
Paul Jakmab881c702010-11-23 16:35:42 +00001072 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001073}
1074
1075/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001076static int
paul718e3742002-12-13 20:15:29 +00001077bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1078 struct attr *attr, u_char flag)
1079{
1080 if (length != 0)
1081 {
1082 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1083
Paul Jakmab881c702010-11-23 16:35:42 +00001084 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1085 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1086 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001087 }
1088
1089 /* Set atomic aggregate flag. */
1090 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1091
Paul Jakmab881c702010-11-23 16:35:42 +00001092 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001093}
1094
1095/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001096static int
paul718e3742002-12-13 20:15:29 +00001097bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1098 struct attr *attr, u_char flag)
1099{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001100 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001101 struct attr_extra *attre = bgp_attr_extra_get (attr);
1102
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001103 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001104 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001105 wantedlen = 8;
1106
1107 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001108 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001109 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001110
Paul Jakmab881c702010-11-23 16:35:42 +00001111 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1112 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1113 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001114 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001115
1116 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1117 attre->aggregator_as = stream_getl (peer->ibuf);
1118 else
1119 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001120 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001121
1122 /* Set atomic aggregate flag. */
1123 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1124
Paul Jakmab881c702010-11-23 16:35:42 +00001125 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001126}
1127
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001128/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001129static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001130bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001131 struct attr *attr, u_char flag,
1132 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001133 struct in_addr *as4_aggregator_addr)
1134{
1135 if (length != 8)
1136 {
1137 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001138 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1139 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1140 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001141 }
1142 *as4_aggregator_as = stream_getl (peer->ibuf);
1143 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1144
1145 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1146
Paul Jakmab881c702010-11-23 16:35:42 +00001147 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001148}
1149
1150/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1151 */
Paul Jakmab881c702010-11-23 16:35:42 +00001152static bgp_attr_parse_ret_t
1153bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001154 struct aspath *as4_path, as_t as4_aggregator,
1155 struct in_addr *as4_aggregator_addr)
1156{
1157 int ignore_as4_path = 0;
1158 struct aspath *newpath;
1159 struct attr_extra *attre = attr->extra;
1160
Paul Jakmab881c702010-11-23 16:35:42 +00001161 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001162 {
1163 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1164 * if given.
1165 * It is worth a warning though, because the peer really
1166 * should not send them
1167 */
1168 if (BGP_DEBUG(as4, AS4))
1169 {
1170 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1171 zlog_debug ("[AS4] %s %s AS4_PATH",
1172 peer->host, "AS4 capable peer, yet it sent");
1173
1174 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1175 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1176 peer->host, "AS4 capable peer, yet it sent");
1177 }
1178
Paul Jakmab881c702010-11-23 16:35:42 +00001179 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001180 }
1181
Paul Jakmab881c702010-11-23 16:35:42 +00001182 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1183 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001184 {
1185 /* Hu? This is not supposed to happen at all!
1186 * got as4_path and no aspath,
1187 * This should already
1188 * have been handled by 'well known attributes missing'
1189 * But... yeah, paranoia
1190 * Take this as a "malformed attribute"
1191 */
1192 zlog (peer->log, LOG_ERR,
1193 "%s BGP not AS4 capable peer sent AS4_PATH but"
1194 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001195 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1196 BGP_NOTIFY_UPDATE_MAL_ATTR,
1197 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001198 }
1199
1200 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1201 * because that may override AS4_PATH
1202 */
1203 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1204 {
Paul Jakmab881c702010-11-23 16:35:42 +00001205 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001206 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001207 assert (attre);
1208
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001209 /* received both.
1210 * if the as_number in aggregator is not AS_TRANS,
1211 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1212 * and the Aggregator shall be taken as
1213 * info on the aggregating node, and the AS_PATH
1214 * shall be taken as the AS_PATH
1215 * otherwise
1216 * the Aggregator shall be ignored and the
1217 * AS4_AGGREGATOR shall be taken as the
1218 * Aggregating node and the AS_PATH is to be
1219 * constructed "as in all other cases"
1220 */
Paul Jakmab881c702010-11-23 16:35:42 +00001221 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001222 {
1223 /* ignore */
1224 if ( BGP_DEBUG(as4, AS4))
1225 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1226 " send AGGREGATOR != AS_TRANS and"
1227 " AS4_AGGREGATOR, so ignore"
1228 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1229 ignore_as4_path = 1;
1230 }
1231 else
1232 {
1233 /* "New_aggregator shall be taken as aggregator" */
1234 attre->aggregator_as = as4_aggregator;
1235 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1236 }
1237 }
1238 else
1239 {
1240 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1241 * That is bogus - but reading the conditions
1242 * we have to handle AS4_AGGREGATOR as if it were
1243 * AGGREGATOR in that case
1244 */
1245 if ( BGP_DEBUG(as4, AS4))
1246 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1247 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1248 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001249 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001250 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1251 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1252 }
1253 }
1254
1255 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001256 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001257 {
1258 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001259 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001260 attr->aspath = aspath_intern (newpath);
1261 }
Paul Jakmab881c702010-11-23 16:35:42 +00001262 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001263}
1264
paul718e3742002-12-13 20:15:29 +00001265/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001266static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001267bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001268 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001269{
Paul Jakmab881c702010-11-23 16:35:42 +00001270 bgp_size_t total
1271 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1272
paul718e3742002-12-13 20:15:29 +00001273 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001274 {
1275 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001276 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001277 }
Paul Jakma0c466382010-12-05 17:17:26 +00001278
1279 attr->community =
1280 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1281
1282 /* XXX: fix community_parse to use stream API and remove this */
1283 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001284
Paul Jakma0c466382010-12-05 17:17:26 +00001285 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001286 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1287 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1288 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001289
paul718e3742002-12-13 20:15:29 +00001290 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1291
Paul Jakmab881c702010-11-23 16:35:42 +00001292 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001293}
1294
1295/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001296static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001297bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1298 struct attr *attr, u_char flag)
1299{
1300 if (length != 4)
1301 {
1302 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1303
Paul Jakmab881c702010-11-23 16:35:42 +00001304 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1305 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1306 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001307 }
1308
Paul Jakmafb982c22007-05-04 20:15:47 +00001309 (bgp_attr_extra_get (attr))->originator_id.s_addr
1310 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001311
1312 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1313
Paul Jakmab881c702010-11-23 16:35:42 +00001314 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001315}
1316
1317/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001318static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001319bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1320 struct attr *attr, u_char flag)
1321{
1322 /* Check length. */
1323 if (length % 4)
1324 {
1325 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1326
Paul Jakmab881c702010-11-23 16:35:42 +00001327 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1328 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1329 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001330 }
1331
Paul Jakmafb982c22007-05-04 20:15:47 +00001332 (bgp_attr_extra_get (attr))->cluster
1333 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001334
1335 /* XXX: Fix cluster_parse to use stream API and then remove this */
1336 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001337
1338 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1339
Paul Jakmab881c702010-11-23 16:35:42 +00001340 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001341}
1342
1343/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001344int
paul718e3742002-12-13 20:15:29 +00001345bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1346 struct bgp_nlri *mp_update)
1347{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001348 afi_t afi;
1349 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001350 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001351 size_t start;
paul718e3742002-12-13 20:15:29 +00001352 int ret;
1353 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001354 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001355
1356 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001357 s = BGP_INPUT(peer);
1358 start = stream_get_getp(s);
1359
1360 /* safe to read statically sized header? */
1361#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001362#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001363 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001364 {
1365 zlog_info ("%s: %s sent invalid length, %lu",
1366 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001367 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001368 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001369
paul718e3742002-12-13 20:15:29 +00001370 /* Load AFI, SAFI. */
1371 afi = stream_getw (s);
1372 safi = stream_getc (s);
1373
1374 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001375 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001376
Paul Jakma03292802008-06-07 20:37:10 +00001377 if (LEN_LEFT < attre->mp_nexthop_len)
1378 {
1379 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1380 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001381 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001382 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001383
paul718e3742002-12-13 20:15:29 +00001384 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001385 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001386 {
1387 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001388 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001389 /* Probably needed for RFC 2283 */
1390 if (attr->nexthop.s_addr == 0)
1391 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001392 break;
1393 case 12:
1394 {
1395 u_int32_t rd_high;
1396 u_int32_t rd_low;
1397
1398 rd_high = stream_getl (s);
1399 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001400 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001401 }
1402 break;
1403#ifdef HAVE_IPV6
1404 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001405 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001406 break;
1407 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001408 stream_get (&attre->mp_nexthop_global, s, 16);
1409 stream_get (&attre->mp_nexthop_local, s, 16);
1410 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001411 {
1412 char buf1[INET6_ADDRSTRLEN];
1413 char buf2[INET6_ADDRSTRLEN];
1414
1415 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001416 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 +00001417 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001418 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001419 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001420 buf2, INET6_ADDRSTRLEN));
1421
Paul Jakmafb982c22007-05-04 20:15:47 +00001422 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001423 }
1424 break;
1425#endif /* HAVE_IPV6 */
1426 default:
Paul Jakma03292802008-06-07 20:37:10 +00001427 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1428 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001429 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001430 }
1431
Paul Jakma03292802008-06-07 20:37:10 +00001432 if (!LEN_LEFT)
1433 {
1434 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1435 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001436 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001437 }
paul718e3742002-12-13 20:15:29 +00001438
Paul Jakma6e4ab122007-04-10 19:36:48 +00001439 {
1440 u_char val;
1441 if ((val = stream_getc (s)))
1442 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1443 peer->host, val);
1444 }
1445
1446 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001447 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001448 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001449 {
1450 zlog_info ("%s: (%s) Failed to read NLRI",
1451 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001452 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001453 }
paul718e3742002-12-13 20:15:29 +00001454
1455 if (safi != BGP_SAFI_VPNV4)
1456 {
1457 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001458 if (ret < 0)
1459 {
1460 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1461 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001462 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001463 }
paul718e3742002-12-13 20:15:29 +00001464 }
1465
1466 mp_update->afi = afi;
1467 mp_update->safi = safi;
1468 mp_update->nlri = stream_pnt (s);
1469 mp_update->length = nlri_len;
1470
paul9985f832005-02-09 15:51:56 +00001471 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001472
Paul Jakmab881c702010-11-23 16:35:42 +00001473 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001474#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001475}
1476
1477/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001478int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001479bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001480 struct bgp_nlri *mp_withdraw)
1481{
1482 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001483 afi_t afi;
1484 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001485 u_int16_t withdraw_len;
1486 int ret;
1487
1488 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001489
1490#define BGP_MP_UNREACH_MIN_SIZE 3
1491 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001492 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001493
paul718e3742002-12-13 20:15:29 +00001494 afi = stream_getw (s);
1495 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001496
1497 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001498
1499 if (safi != BGP_SAFI_VPNV4)
1500 {
1501 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1502 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001503 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001504 }
1505
1506 mp_withdraw->afi = afi;
1507 mp_withdraw->safi = safi;
1508 mp_withdraw->nlri = stream_pnt (s);
1509 mp_withdraw->length = withdraw_len;
1510
paul9985f832005-02-09 15:51:56 +00001511 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001512
Paul Jakmab881c702010-11-23 16:35:42 +00001513 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001514}
1515
1516/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001517static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001518bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001519 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001520{
Paul Jakmab881c702010-11-23 16:35:42 +00001521 bgp_size_t total
1522 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1523
paul718e3742002-12-13 20:15:29 +00001524 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001525 {
1526 if (attr->extra)
1527 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001528 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001529 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001530 }
Paul Jakma0c466382010-12-05 17:17:26 +00001531
1532 (bgp_attr_extra_get (attr))->ecommunity =
1533 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1534 /* XXX: fix ecommunity_parse to use stream API */
1535 stream_forward_getp (peer->ibuf, length);
1536
1537 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001538 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1539 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1540 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001541
paul718e3742002-12-13 20:15:29 +00001542 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1543
Paul Jakmab881c702010-11-23 16:35:42 +00001544 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001545}
1546
1547/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001548static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001549bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1550 u_char type, bgp_size_t length, u_char *startp)
1551{
1552 bgp_size_t total;
1553 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001554 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001555
hassof4184462005-02-01 20:13:16 +00001556 if (BGP_DEBUG (normal, NORMAL))
1557 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1558 peer->host, type, length);
1559
paul718e3742002-12-13 20:15:29 +00001560 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001561 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001562 "Unknown attribute type %d length %d is received", type, length);
1563
1564 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001565 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001566
1567 /* Adjest total length to include type and length. */
1568 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1569
1570 /* If any of the mandatory well-known attributes are not recognized,
1571 then the Error Subcode is set to Unrecognized Well-known
1572 Attribute. The Data field contains the unrecognized attribute
1573 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001574 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001575 {
Paul Jakmab881c702010-11-23 16:35:42 +00001576 return bgp_attr_malformed (peer, type, flag,
1577 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1578 startp, total);
paul718e3742002-12-13 20:15:29 +00001579 }
1580
1581 /* Unrecognized non-transitive optional attributes must be quietly
1582 ignored and not passed along to other BGP peers. */
1583 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001584 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001585
1586 /* If a path with recognized transitive optional attribute is
1587 accepted and passed along to other BGP peers and the Partial bit
1588 in the Attribute Flags octet is set to 1 by some previous AS, it
1589 is not set back to 0 by the current AS. */
1590 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1591
1592 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001593 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001594 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001595
Paul Jakmafb982c22007-05-04 20:15:47 +00001596 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001597
1598 if (transit->val)
1599 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1600 transit->length + total);
1601 else
1602 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1603
1604 memcpy (transit->val + transit->length, startp, total);
1605 transit->length += total;
1606
Paul Jakmab881c702010-11-23 16:35:42 +00001607 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001608}
1609
1610/* Read attribute of update packet. This function is called from
1611 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001612bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001613bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1614 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1615{
1616 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001617 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001618 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001619 bgp_size_t length;
1620 u_char *startp, *endp;
1621 u_char *attr_endp;
1622 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001623 /* we need the as4_path only until we have synthesized the as_path with it */
1624 /* same goes for as4_aggregator */
1625 struct aspath *as4_path = NULL;
1626 as_t as4_aggregator = 0;
1627 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001628
1629 /* Initialize bitmap. */
1630 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1631
1632 /* End pointer of BGP attribute. */
1633 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001634
paul718e3742002-12-13 20:15:29 +00001635 /* Get attributes to the end of attribute length. */
1636 while (BGP_INPUT_PNT (peer) < endp)
1637 {
1638 /* Check remaining length check.*/
1639 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1640 {
gdtc29fdba2004-12-09 14:46:46 +00001641 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001642 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001643 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001644 peer->host,
1645 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001646
1647 bgp_notify_send (peer,
1648 BGP_NOTIFY_UPDATE_ERR,
1649 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001650 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001651 }
1652
1653 /* Fetch attribute flag and type. */
1654 startp = BGP_INPUT_PNT (peer);
1655 flag = stream_getc (BGP_INPUT (peer));
1656 type = stream_getc (BGP_INPUT (peer));
1657
Paul Jakma370b64a2007-12-22 16:49:52 +00001658 /* Check whether Extended-Length applies and is in bounds */
1659 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1660 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1661 {
1662 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001663 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001664 peer->host,
1665 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1666
1667 bgp_notify_send (peer,
1668 BGP_NOTIFY_UPDATE_ERR,
1669 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001670 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001671 }
1672
paul718e3742002-12-13 20:15:29 +00001673 /* Check extended attribue length bit. */
1674 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1675 length = stream_getw (BGP_INPUT (peer));
1676 else
1677 length = stream_getc (BGP_INPUT (peer));
1678
1679 /* If any attribute appears more than once in the UPDATE
1680 message, then the Error Subcode is set to Malformed Attribute
1681 List. */
1682
1683 if (CHECK_BITMAP (seen, type))
1684 {
1685 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001686 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001687 peer->host, type);
1688
1689 bgp_notify_send (peer,
1690 BGP_NOTIFY_UPDATE_ERR,
1691 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001692 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001693 }
1694
1695 /* Set type to bitmap to check duplicate attribute. `type' is
1696 unsigned char so it never overflow bitmap range. */
1697
1698 SET_BITMAP (seen, type);
1699
1700 /* Overflow check. */
1701 attr_endp = BGP_INPUT_PNT (peer) + length;
1702
1703 if (attr_endp > endp)
1704 {
1705 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001706 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
paul718e3742002-12-13 20:15:29 +00001707 bgp_notify_send (peer,
1708 BGP_NOTIFY_UPDATE_ERR,
1709 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001710 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001711 }
1712
1713 /* OK check attribute and store it's value. */
1714 switch (type)
1715 {
1716 case BGP_ATTR_ORIGIN:
1717 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1718 break;
1719 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001720 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001721 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001722 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001723 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001724 break;
paul718e3742002-12-13 20:15:29 +00001725 case BGP_ATTR_NEXT_HOP:
1726 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1727 break;
1728 case BGP_ATTR_MULTI_EXIT_DISC:
1729 ret = bgp_attr_med (peer, length, attr, flag, startp);
1730 break;
1731 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001732 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001733 break;
1734 case BGP_ATTR_ATOMIC_AGGREGATE:
1735 ret = bgp_attr_atomic (peer, length, attr, flag);
1736 break;
1737 case BGP_ATTR_AGGREGATOR:
1738 ret = bgp_attr_aggregator (peer, length, attr, flag);
1739 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001740 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001741 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1742 &as4_aggregator,
1743 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001744 break;
paul718e3742002-12-13 20:15:29 +00001745 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001746 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001747 break;
1748 case BGP_ATTR_ORIGINATOR_ID:
1749 ret = bgp_attr_originator_id (peer, length, attr, flag);
1750 break;
1751 case BGP_ATTR_CLUSTER_LIST:
1752 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1753 break;
1754 case BGP_ATTR_MP_REACH_NLRI:
1755 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1756 break;
1757 case BGP_ATTR_MP_UNREACH_NLRI:
1758 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1759 break;
1760 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001761 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001762 break;
1763 default:
1764 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1765 break;
1766 }
Paul Jakmab881c702010-11-23 16:35:42 +00001767
1768 /* If hard error occured immediately return to the caller. */
1769 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001770 {
1771 zlog (peer->log, LOG_WARNING,
1772 "%s: Attribute %s, parse error",
1773 peer->host,
1774 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001775 bgp_notify_send (peer,
1776 BGP_NOTIFY_UPDATE_ERR,
1777 BGP_NOTIFY_UPDATE_MAL_ATTR);
1778 if (as4_path)
1779 aspath_unintern (&as4_path);
1780 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001781 }
Paul Jakmab881c702010-11-23 16:35:42 +00001782 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1783 {
1784
1785 zlog (peer->log, LOG_WARNING,
1786 "%s: Attribute %s, parse error - treating as withdrawal",
1787 peer->host,
1788 LOOKUP (attr_str, type));
1789 if (as4_path)
1790 aspath_unintern (&as4_path);
1791 return ret;
1792 }
1793
paul718e3742002-12-13 20:15:29 +00001794 /* Check the fetched length. */
1795 if (BGP_INPUT_PNT (peer) != attr_endp)
1796 {
1797 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001798 "%s: BGP attribute %s, fetch error",
1799 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001800 bgp_notify_send (peer,
1801 BGP_NOTIFY_UPDATE_ERR,
1802 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001803 if (as4_path)
1804 aspath_unintern (&as4_path);
1805 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001806 }
1807 }
1808
1809 /* Check final read pointer is same as end pointer. */
1810 if (BGP_INPUT_PNT (peer) != endp)
1811 {
1812 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001813 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001814 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001815 bgp_notify_send (peer,
1816 BGP_NOTIFY_UPDATE_ERR,
1817 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001818 if (as4_path)
1819 aspath_unintern (&as4_path);
1820 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001821 }
1822
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001823 /*
1824 * At this place we can see whether we got AS4_PATH and/or
1825 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1826 * We can not do this before we've read all attributes because
1827 * the as4 handling does not say whether AS4_PATH has to be sent
1828 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1829 * in relationship to AGGREGATOR.
1830 * So, to be defensive, we are not relying on any order and read
1831 * all attributes first, including these 32bit ones, and now,
1832 * afterwards, we look what and if something is to be done for as4.
1833 */
Paul Jakmab881c702010-11-23 16:35:42 +00001834 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001835 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001836 {
1837 if (as4_path)
1838 aspath_unintern (&as4_path);
1839 return BGP_ATTR_PARSE_ERROR;
1840 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001841
1842 /* At this stage, we have done all fiddling with as4, and the
1843 * resulting info is in attr->aggregator resp. attr->aspath
1844 * so we can chuck as4_aggregator and as4_path alltogether in
1845 * order to save memory
1846 */
Paul Jakmab881c702010-11-23 16:35:42 +00001847 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001848 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001849 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001850 /* The flag that we got this is still there, but that does not
1851 * do any trouble
1852 */
1853 }
1854 /*
1855 * The "rest" of the code does nothing with as4_aggregator.
1856 * there is no memory attached specifically which is not part
1857 * of the attr.
1858 * so ignoring just means do nothing.
1859 */
1860 /*
1861 * Finally do the checks on the aspath we did not do yet
1862 * because we waited for a potentially synthesized aspath.
1863 */
Paul Jakmab881c702010-11-23 16:35:42 +00001864 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001865 {
Paul Jakmab881c702010-11-23 16:35:42 +00001866 ret = bgp_attr_aspath_check (peer, attr, flag);
1867 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001868 return ret;
1869 }
1870
paul718e3742002-12-13 20:15:29 +00001871 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001872 if (attr->extra && attr->extra->transit)
1873 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001874
Paul Jakmab881c702010-11-23 16:35:42 +00001875 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001876}
1877
1878/* Well-known attribute check. */
1879int
1880bgp_attr_check (struct peer *peer, struct attr *attr)
1881{
1882 u_char type = 0;
1883
1884 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1885 type = BGP_ATTR_ORIGIN;
1886
1887 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1888 type = BGP_ATTR_AS_PATH;
1889
1890 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1891 type = BGP_ATTR_NEXT_HOP;
1892
1893 if (peer_sort (peer) == BGP_PEER_IBGP
1894 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1895 type = BGP_ATTR_LOCAL_PREF;
1896
1897 if (type)
1898 {
1899 zlog (peer->log, LOG_WARNING,
1900 "%s Missing well-known attribute %d.",
1901 peer->host, type);
1902 bgp_notify_send_with_data (peer,
1903 BGP_NOTIFY_UPDATE_ERR,
1904 BGP_NOTIFY_UPDATE_MISS_ATTR,
1905 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00001906 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001907 }
Paul Jakmab881c702010-11-23 16:35:42 +00001908 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001909}
1910
1911int stream_put_prefix (struct stream *, struct prefix *);
1912
1913/* Make attribute packet. */
1914bgp_size_t
1915bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1916 struct stream *s, struct attr *attr, struct prefix *p,
1917 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001918 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001919{
paulfe69a502005-09-10 16:55:02 +00001920 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001921 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001922 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001923 int send_as4_path = 0;
1924 int send_as4_aggregator = 0;
1925 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001926
1927 if (! bgp)
1928 bgp = bgp_get_default ();
1929
1930 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001931 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001932
1933 /* Origin attribute. */
1934 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1935 stream_putc (s, BGP_ATTR_ORIGIN);
1936 stream_putc (s, 1);
1937 stream_putc (s, attr->origin);
1938
1939 /* AS path attribute. */
1940
1941 /* If remote-peer is EBGP */
1942 if (peer_sort (peer) == BGP_PEER_EBGP
1943 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001944 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001945 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001946 {
1947 aspath = aspath_dup (attr->aspath);
1948
1949 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1950 {
1951 /* Strip the confed info, and then stuff our path CONFED_ID
1952 on the front */
1953 aspath = aspath_delete_confed_seq (aspath);
1954 aspath = aspath_add_seq (aspath, bgp->confed_id);
1955 }
1956 else
1957 {
1958 aspath = aspath_add_seq (aspath, peer->local_as);
1959 if (peer->change_local_as)
1960 aspath = aspath_add_seq (aspath, peer->change_local_as);
1961 }
1962 }
1963 else if (peer_sort (peer) == BGP_PEER_CONFED)
1964 {
1965 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1966 aspath = aspath_dup (attr->aspath);
1967 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1968 }
1969 else
1970 aspath = attr->aspath;
1971
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001972 /* If peer is not AS4 capable, then:
1973 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1974 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1975 * types are in it (i.e. exclude them if they are there)
1976 * AND do this only if there is at least one asnum > 65535 in the path!
1977 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1978 * all ASnums > 65535 to BGP_AS_TRANS
1979 */
paul718e3742002-12-13 20:15:29 +00001980
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001981 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1982 stream_putc (s, BGP_ATTR_AS_PATH);
1983 aspath_sizep = stream_get_endp (s);
1984 stream_putw (s, 0);
1985 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1986
1987 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1988 * in the path
1989 */
1990 if (!use32bit && aspath_has_as4 (aspath))
1991 send_as4_path = 1; /* we'll do this later, at the correct place */
1992
paul718e3742002-12-13 20:15:29 +00001993 /* Nexthop attribute. */
1994 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1995 {
1996 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1997 stream_putc (s, BGP_ATTR_NEXT_HOP);
1998 stream_putc (s, 4);
1999 if (safi == SAFI_MPLS_VPN)
2000 {
2001 if (attr->nexthop.s_addr == 0)
2002 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2003 else
2004 stream_put_ipv4 (s, attr->nexthop.s_addr);
2005 }
2006 else
2007 stream_put_ipv4 (s, attr->nexthop.s_addr);
2008 }
2009
2010 /* MED attribute. */
2011 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2012 {
2013 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2014 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2015 stream_putc (s, 4);
2016 stream_putl (s, attr->med);
2017 }
2018
2019 /* Local preference. */
2020 if (peer_sort (peer) == BGP_PEER_IBGP ||
2021 peer_sort (peer) == BGP_PEER_CONFED)
2022 {
2023 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2024 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2025 stream_putc (s, 4);
2026 stream_putl (s, attr->local_pref);
2027 }
2028
2029 /* Atomic aggregate. */
2030 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2031 {
2032 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2033 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2034 stream_putc (s, 0);
2035 }
2036
2037 /* Aggregator. */
2038 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2039 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002040 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002041
2042 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002043 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2044 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002045
2046 if (use32bit)
2047 {
2048 /* AS4 capable peer */
2049 stream_putc (s, 8);
2050 stream_putl (s, attr->extra->aggregator_as);
2051 }
2052 else
2053 {
2054 /* 2-byte AS peer */
2055 stream_putc (s, 6);
2056
2057 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2058 if ( attr->extra->aggregator_as > 65535 )
2059 {
2060 stream_putw (s, BGP_AS_TRANS);
2061
2062 /* we have to send AS4_AGGREGATOR, too.
2063 * we'll do that later in order to send attributes in ascending
2064 * order.
2065 */
2066 send_as4_aggregator = 1;
2067 }
2068 else
2069 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2070 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002072 }
2073
2074 /* Community attribute. */
2075 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2076 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2077 {
2078 if (attr->community->size * 4 > 255)
2079 {
2080 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2081 stream_putc (s, BGP_ATTR_COMMUNITIES);
2082 stream_putw (s, attr->community->size * 4);
2083 }
2084 else
2085 {
2086 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2087 stream_putc (s, BGP_ATTR_COMMUNITIES);
2088 stream_putc (s, attr->community->size * 4);
2089 }
2090 stream_put (s, attr->community->val, attr->community->size * 4);
2091 }
2092
2093 /* Route Reflector. */
2094 if (peer_sort (peer) == BGP_PEER_IBGP
2095 && from
2096 && peer_sort (from) == BGP_PEER_IBGP)
2097 {
2098 /* Originator ID. */
2099 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2100 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2101 stream_putc (s, 4);
2102
2103 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002104 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002105 else
2106 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002107
2108 /* Cluster list. */
2109 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2110 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2111
Paul Jakma9eda90c2007-08-30 13:36:17 +00002112 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002113 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002114 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002115 /* If this peer configuration's parent BGP has cluster_id. */
2116 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2117 stream_put_in_addr (s, &bgp->cluster_id);
2118 else
2119 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002120 stream_put (s, attr->extra->cluster->list,
2121 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002122 }
2123 else
2124 {
2125 stream_putc (s, 4);
2126 /* If this peer configuration's parent BGP has cluster_id. */
2127 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2128 stream_put_in_addr (s, &bgp->cluster_id);
2129 else
2130 stream_put_in_addr (s, &bgp->router_id);
2131 }
2132 }
2133
2134#ifdef HAVE_IPV6
2135 /* If p is IPv6 address put it into attribute. */
2136 if (p->family == AF_INET6)
2137 {
2138 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002139 struct attr_extra *attre = attr->extra;
2140
2141 assert (attr->extra);
2142
paul718e3742002-12-13 20:15:29 +00002143 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2144 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002145 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002147 stream_putw (s, AFI_IP6); /* AFI */
2148 stream_putc (s, safi); /* SAFI */
2149
Paul Jakmafb982c22007-05-04 20:15:47 +00002150 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002151
Paul Jakmafb982c22007-05-04 20:15:47 +00002152 if (attre->mp_nexthop_len == 16)
2153 stream_put (s, &attre->mp_nexthop_global, 16);
2154 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002155 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002156 stream_put (s, &attre->mp_nexthop_global, 16);
2157 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002158 }
2159
2160 /* SNPA */
2161 stream_putc (s, 0);
2162
paul718e3742002-12-13 20:15:29 +00002163 /* Prefix write. */
2164 stream_put_prefix (s, p);
2165
2166 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002167 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002168 }
2169#endif /* HAVE_IPV6 */
2170
2171 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2172 {
2173 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002174
2175 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2176 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002177 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002178 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002179 stream_putw (s, AFI_IP); /* AFI */
2180 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2181
2182 stream_putc (s, 4);
2183 stream_put_ipv4 (s, attr->nexthop.s_addr);
2184
2185 /* SNPA */
2186 stream_putc (s, 0);
2187
paul718e3742002-12-13 20:15:29 +00002188 /* Prefix write. */
2189 stream_put_prefix (s, p);
2190
2191 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002192 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002193 }
2194
2195 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2196 {
2197 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002198
2199 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2200 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002201 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002202 stream_putc (s, 0); /* Length of this attribute. */
2203 stream_putw (s, AFI_IP); /* AFI */
2204 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2205
2206 stream_putc (s, 12);
2207 stream_putl (s, 0);
2208 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002209 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002210
2211 /* SNPA */
2212 stream_putc (s, 0);
2213
paul718e3742002-12-13 20:15:29 +00002214 /* Tag, RD, Prefix write. */
2215 stream_putc (s, p->prefixlen + 88);
2216 stream_put (s, tag, 3);
2217 stream_put (s, prd->val, 8);
2218 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2219
2220 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002221 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002222 }
2223
2224 /* Extended Communities attribute. */
2225 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2226 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2227 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002228 struct attr_extra *attre = attr->extra;
2229
2230 assert (attre);
2231
2232 if (peer_sort (peer) == BGP_PEER_IBGP
2233 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002234 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002235 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002236 {
2237 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2238 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002239 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002240 }
2241 else
2242 {
2243 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2244 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002245 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002246 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002247 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002248 }
2249 else
2250 {
paul5228ad22004-06-04 17:58:18 +00002251 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002252 int tbit;
2253 int ecom_tr_size = 0;
2254 int i;
2255
Paul Jakmafb982c22007-05-04 20:15:47 +00002256 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002257 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002258 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002259 tbit = *pnt;
2260
2261 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2262 continue;
2263
2264 ecom_tr_size++;
2265 }
2266
2267 if (ecom_tr_size)
2268 {
2269 if (ecom_tr_size * 8 > 255)
2270 {
2271 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2272 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2273 stream_putw (s, ecom_tr_size * 8);
2274 }
2275 else
2276 {
2277 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2278 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2279 stream_putc (s, ecom_tr_size * 8);
2280 }
2281
Paul Jakmafb982c22007-05-04 20:15:47 +00002282 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002283 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002284 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002285 tbit = *pnt;
2286
2287 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2288 continue;
2289
2290 stream_put (s, pnt, 8);
2291 }
2292 }
paul718e3742002-12-13 20:15:29 +00002293 }
paul718e3742002-12-13 20:15:29 +00002294 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002295
2296 if ( send_as4_path )
2297 {
2298 /* If the peer is NOT As4 capable, AND */
2299 /* there are ASnums > 65535 in path THEN
2300 * give out AS4_PATH */
2301
2302 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2303 * path segments!
2304 * Hm, I wonder... confederation things *should* only be at
2305 * the beginning of an aspath, right? Then we should use
2306 * aspath_delete_confed_seq for this, because it is already
2307 * there! (JK)
2308 * Folks, talk to me: what is reasonable here!?
2309 */
2310 aspath = aspath_delete_confed_seq (aspath);
2311
2312 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2313 stream_putc (s, BGP_ATTR_AS4_PATH);
2314 aspath_sizep = stream_get_endp (s);
2315 stream_putw (s, 0);
2316 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2317 }
2318
2319 if (aspath != attr->aspath)
2320 aspath_free (aspath);
2321
2322 if ( send_as4_aggregator )
2323 {
2324 assert (attr->extra);
2325
2326 /* send AS4_AGGREGATOR, at this place */
2327 /* this section of code moved here in order to ensure the correct
2328 * *ascending* order of attributes
2329 */
2330 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2331 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2332 stream_putc (s, 8);
2333 stream_putl (s, attr->extra->aggregator_as);
2334 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2335 }
Paul Jakma41367172007-08-06 15:24:51 +00002336
paul718e3742002-12-13 20:15:29 +00002337 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002338 if (attr->extra && attr->extra->transit)
2339 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002340
2341 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002342 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002343}
2344
2345bgp_size_t
2346bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2347 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002348 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002349{
2350 unsigned long cp;
2351 unsigned long attrlen_pnt;
2352 bgp_size_t size;
2353
paul9985f832005-02-09 15:51:56 +00002354 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002355
2356 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2357 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2358
paul9985f832005-02-09 15:51:56 +00002359 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002360 stream_putc (s, 0); /* Length of this attribute. */
2361
2362 stream_putw (s, family2afi (p->family));
2363
2364 if (safi == SAFI_MPLS_VPN)
2365 {
2366 /* SAFI */
2367 stream_putc (s, BGP_SAFI_VPNV4);
2368
2369 /* prefix. */
2370 stream_putc (s, p->prefixlen + 88);
2371 stream_put (s, tag, 3);
2372 stream_put (s, prd->val, 8);
2373 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2374 }
2375 else
2376 {
2377 /* SAFI */
2378 stream_putc (s, safi);
2379
2380 /* prefix */
2381 stream_put_prefix (s, p);
2382 }
2383
2384 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002385 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002386 stream_putc_at (s, attrlen_pnt, size);
2387
paul9985f832005-02-09 15:51:56 +00002388 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002389}
2390
2391/* Initialization of attribute. */
2392void
paulfe69a502005-09-10 16:55:02 +00002393bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002394{
paul718e3742002-12-13 20:15:29 +00002395 aspath_init ();
2396 attrhash_init ();
2397 community_init ();
2398 ecommunity_init ();
2399 cluster_init ();
2400 transit_init ();
2401}
2402
Chris Caputo228da422009-07-18 05:44:03 +00002403void
2404bgp_attr_finish (void)
2405{
2406 aspath_finish ();
2407 attrhash_finish ();
2408 community_finish ();
2409 ecommunity_finish ();
2410 cluster_finish ();
2411 transit_finish ();
2412}
2413
paul718e3742002-12-13 20:15:29 +00002414/* Make attribute packet. */
2415void
paula3845922003-10-18 01:30:50 +00002416bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2417 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002418{
2419 unsigned long cp;
2420 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002421 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002422 struct aspath *aspath;
2423
2424 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002425 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002426
2427 /* Place holder of length. */
2428 stream_putw (s, 0);
2429
2430 /* Origin attribute. */
2431 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2432 stream_putc (s, BGP_ATTR_ORIGIN);
2433 stream_putc (s, 1);
2434 stream_putc (s, attr->origin);
2435
2436 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002437
2438 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2439 stream_putc (s, BGP_ATTR_AS_PATH);
2440 aspath_lenp = stream_get_endp (s);
2441 stream_putw (s, 0);
2442
2443 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002444
2445 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002446 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2447 if(prefix != NULL
2448#ifdef HAVE_IPV6
2449 && prefix->family != AF_INET6
2450#endif /* HAVE_IPV6 */
2451 )
2452 {
2453 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2454 stream_putc (s, BGP_ATTR_NEXT_HOP);
2455 stream_putc (s, 4);
2456 stream_put_ipv4 (s, attr->nexthop.s_addr);
2457 }
paul718e3742002-12-13 20:15:29 +00002458
2459 /* MED attribute. */
2460 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2461 {
2462 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2463 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2464 stream_putc (s, 4);
2465 stream_putl (s, attr->med);
2466 }
2467
2468 /* Local preference. */
2469 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2470 {
2471 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2472 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2473 stream_putc (s, 4);
2474 stream_putl (s, attr->local_pref);
2475 }
2476
2477 /* Atomic aggregate. */
2478 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2479 {
2480 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2481 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2482 stream_putc (s, 0);
2483 }
2484
2485 /* Aggregator. */
2486 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2487 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002488 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002489 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2490 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002491 stream_putc (s, 8);
2492 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002493 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002494 }
2495
2496 /* Community attribute. */
2497 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2498 {
2499 if (attr->community->size * 4 > 255)
2500 {
2501 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2502 stream_putc (s, BGP_ATTR_COMMUNITIES);
2503 stream_putw (s, attr->community->size * 4);
2504 }
2505 else
2506 {
2507 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2508 stream_putc (s, BGP_ATTR_COMMUNITIES);
2509 stream_putc (s, attr->community->size * 4);
2510 }
2511 stream_put (s, attr->community->val, attr->community->size * 4);
2512 }
2513
paula3845922003-10-18 01:30:50 +00002514#ifdef HAVE_IPV6
2515 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002516 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2517 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002518 {
2519 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002520 struct attr_extra *attre = attr->extra;
2521
paula3845922003-10-18 01:30:50 +00002522 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2523 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002524 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002525
2526 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002527 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002528 stream_putw(s, AFI_IP6); /* AFI */
2529 stream_putc(s, SAFI_UNICAST); /* SAFI */
2530
2531 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002532 stream_putc(s, attre->mp_nexthop_len);
2533 stream_put(s, &attre->mp_nexthop_global, 16);
2534 if (attre->mp_nexthop_len == 32)
2535 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002536
2537 /* SNPA */
2538 stream_putc(s, 0);
2539
2540 /* Prefix */
2541 stream_put_prefix(s, prefix);
2542
2543 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002544 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002545 }
2546#endif /* HAVE_IPV6 */
2547
paul718e3742002-12-13 20:15:29 +00002548 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002549 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002550 stream_putw_at (s, cp, len);
2551}