blob: a98669945627fb5ac5243bdd2ebfebf802bfa48b [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
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001007 /* Flag checks. */
1008 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1009 {
1010 zlog (peer->log, LOG_ERR,
1011 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1012 bgp_notify_send_with_data (peer,
1013 BGP_NOTIFY_UPDATE_ERR,
1014 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1015 startp, total);
1016 return -1;
1017 }
1018 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1019 {
1020 zlog (peer->log, LOG_ERR,
1021 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1022 bgp_notify_send_with_data (peer,
1023 BGP_NOTIFY_UPDATE_ERR,
1024 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1025 startp, total);
1026 return -1;
1027 }
1028 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1029 {
1030 zlog (peer->log, LOG_ERR,
1031 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
1032 bgp_notify_send_with_data (peer,
1033 BGP_NOTIFY_UPDATE_ERR,
1034 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1035 startp, total);
1036 return -1;
1037 }
1038
paul718e3742002-12-13 20:15:29 +00001039 /* Length check. */
1040 if (length != 4)
1041 {
1042 zlog (peer->log, LOG_ERR,
1043 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001044
1045 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1046 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1047 startp, total);
paul718e3742002-12-13 20:15:29 +00001048 }
1049
1050 attr->med = stream_getl (peer->ibuf);
1051
1052 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1053
Paul Jakmab881c702010-11-23 16:35:42 +00001054 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001055}
1056
1057/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001058static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001059bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001060 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001061{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001062 bgp_size_t total;
1063
1064 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1065 /* Flag checks. */
1066 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1067 {
1068 zlog (peer->log, LOG_ERR,
1069 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1070 bgp_notify_send_with_data (peer,
1071 BGP_NOTIFY_UPDATE_ERR,
1072 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1073 startp, total);
1074 return -1;
1075 }
1076 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1077 {
1078 zlog (peer->log, LOG_ERR,
1079 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1080 bgp_notify_send_with_data (peer,
1081 BGP_NOTIFY_UPDATE_ERR,
1082 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1083 startp, total);
1084 return -1;
1085 }
1086
paul718e3742002-12-13 20:15:29 +00001087 /* If it is contained in an UPDATE message that is received from an
1088 external peer, then this attribute MUST be ignored by the
1089 receiving speaker. */
1090 if (peer_sort (peer) == BGP_PEER_EBGP)
1091 {
paul9985f832005-02-09 15:51:56 +00001092 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001093 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001094 }
1095
1096 if (length == 4)
1097 attr->local_pref = stream_getl (peer->ibuf);
1098 else
1099 attr->local_pref = 0;
1100
1101 /* Set atomic aggregate flag. */
1102 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1103
Paul Jakmab881c702010-11-23 16:35:42 +00001104 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001105}
1106
1107/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001108static int
paul718e3742002-12-13 20:15:29 +00001109bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1110 struct attr *attr, u_char flag)
1111{
1112 if (length != 0)
1113 {
1114 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1115
Paul Jakmab881c702010-11-23 16:35:42 +00001116 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1117 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1118 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001119 }
1120
1121 /* Set atomic aggregate flag. */
1122 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1123
Paul Jakmab881c702010-11-23 16:35:42 +00001124 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001125}
1126
1127/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001128static int
paul718e3742002-12-13 20:15:29 +00001129bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1130 struct attr *attr, u_char flag)
1131{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001132 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001133 struct attr_extra *attre = bgp_attr_extra_get (attr);
1134
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001135 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001136 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001137 wantedlen = 8;
1138
1139 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001140 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001141 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001142
Paul Jakmab881c702010-11-23 16:35:42 +00001143 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1144 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1145 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001146 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001147
1148 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1149 attre->aggregator_as = stream_getl (peer->ibuf);
1150 else
1151 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001152 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001153
1154 /* Set atomic aggregate flag. */
1155 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1156
Paul Jakmab881c702010-11-23 16:35:42 +00001157 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001158}
1159
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001160/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001161static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001162bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001163 struct attr *attr, u_char flag,
1164 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001165 struct in_addr *as4_aggregator_addr)
1166{
1167 if (length != 8)
1168 {
1169 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001170 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1171 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1172 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001173 }
1174 *as4_aggregator_as = stream_getl (peer->ibuf);
1175 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1176
1177 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1178
Paul Jakmab881c702010-11-23 16:35:42 +00001179 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001180}
1181
1182/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1183 */
Paul Jakmab881c702010-11-23 16:35:42 +00001184static bgp_attr_parse_ret_t
1185bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001186 struct aspath *as4_path, as_t as4_aggregator,
1187 struct in_addr *as4_aggregator_addr)
1188{
1189 int ignore_as4_path = 0;
1190 struct aspath *newpath;
1191 struct attr_extra *attre = attr->extra;
1192
Paul Jakmab881c702010-11-23 16:35:42 +00001193 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001194 {
1195 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1196 * if given.
1197 * It is worth a warning though, because the peer really
1198 * should not send them
1199 */
1200 if (BGP_DEBUG(as4, AS4))
1201 {
1202 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1203 zlog_debug ("[AS4] %s %s AS4_PATH",
1204 peer->host, "AS4 capable peer, yet it sent");
1205
1206 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1207 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1208 peer->host, "AS4 capable peer, yet it sent");
1209 }
1210
Paul Jakmab881c702010-11-23 16:35:42 +00001211 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001212 }
1213
Paul Jakmab881c702010-11-23 16:35:42 +00001214 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1215 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001216 {
1217 /* Hu? This is not supposed to happen at all!
1218 * got as4_path and no aspath,
1219 * This should already
1220 * have been handled by 'well known attributes missing'
1221 * But... yeah, paranoia
1222 * Take this as a "malformed attribute"
1223 */
1224 zlog (peer->log, LOG_ERR,
1225 "%s BGP not AS4 capable peer sent AS4_PATH but"
1226 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001227 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1228 BGP_NOTIFY_UPDATE_MAL_ATTR,
1229 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001230 }
1231
1232 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1233 * because that may override AS4_PATH
1234 */
1235 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1236 {
Paul Jakmab881c702010-11-23 16:35:42 +00001237 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001238 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001239 assert (attre);
1240
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001241 /* received both.
1242 * if the as_number in aggregator is not AS_TRANS,
1243 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1244 * and the Aggregator shall be taken as
1245 * info on the aggregating node, and the AS_PATH
1246 * shall be taken as the AS_PATH
1247 * otherwise
1248 * the Aggregator shall be ignored and the
1249 * AS4_AGGREGATOR shall be taken as the
1250 * Aggregating node and the AS_PATH is to be
1251 * constructed "as in all other cases"
1252 */
Paul Jakmab881c702010-11-23 16:35:42 +00001253 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001254 {
1255 /* ignore */
1256 if ( BGP_DEBUG(as4, AS4))
1257 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1258 " send AGGREGATOR != AS_TRANS and"
1259 " AS4_AGGREGATOR, so ignore"
1260 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1261 ignore_as4_path = 1;
1262 }
1263 else
1264 {
1265 /* "New_aggregator shall be taken as aggregator" */
1266 attre->aggregator_as = as4_aggregator;
1267 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1268 }
1269 }
1270 else
1271 {
1272 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1273 * That is bogus - but reading the conditions
1274 * we have to handle AS4_AGGREGATOR as if it were
1275 * AGGREGATOR in that case
1276 */
1277 if ( BGP_DEBUG(as4, AS4))
1278 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1279 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1280 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001281 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001282 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1283 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1284 }
1285 }
1286
1287 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001288 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001289 {
1290 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001291 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001292 attr->aspath = aspath_intern (newpath);
1293 }
Paul Jakmab881c702010-11-23 16:35:42 +00001294 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001295}
1296
paul718e3742002-12-13 20:15:29 +00001297/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001298static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001299bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001300 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001301{
Paul Jakmab881c702010-11-23 16:35:42 +00001302 bgp_size_t total
1303 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1304
paul718e3742002-12-13 20:15:29 +00001305 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001306 {
1307 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001308 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001309 }
Paul Jakma0c466382010-12-05 17:17:26 +00001310
1311 attr->community =
1312 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1313
1314 /* XXX: fix community_parse to use stream API and remove this */
1315 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001316
Paul Jakma0c466382010-12-05 17:17:26 +00001317 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001318 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1319 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1320 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001321
paul718e3742002-12-13 20:15:29 +00001322 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1323
Paul Jakmab881c702010-11-23 16:35:42 +00001324 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001325}
1326
1327/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001328static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001329bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1330 struct attr *attr, u_char flag)
1331{
1332 if (length != 4)
1333 {
1334 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1335
Paul Jakmab881c702010-11-23 16:35:42 +00001336 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1337 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1338 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001339 }
1340
Paul Jakmafb982c22007-05-04 20:15:47 +00001341 (bgp_attr_extra_get (attr))->originator_id.s_addr
1342 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001343
1344 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1345
Paul Jakmab881c702010-11-23 16:35:42 +00001346 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001347}
1348
1349/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001350static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001351bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1352 struct attr *attr, u_char flag)
1353{
1354 /* Check length. */
1355 if (length % 4)
1356 {
1357 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1358
Paul Jakmab881c702010-11-23 16:35:42 +00001359 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1360 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1361 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001362 }
1363
Paul Jakmafb982c22007-05-04 20:15:47 +00001364 (bgp_attr_extra_get (attr))->cluster
1365 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001366
1367 /* XXX: Fix cluster_parse to use stream API and then remove this */
1368 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001369
1370 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1371
Paul Jakmab881c702010-11-23 16:35:42 +00001372 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001373}
1374
1375/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001376int
paul718e3742002-12-13 20:15:29 +00001377bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1378 struct bgp_nlri *mp_update)
1379{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001380 afi_t afi;
1381 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001382 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001383 size_t start;
paul718e3742002-12-13 20:15:29 +00001384 int ret;
1385 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001386 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001387
1388 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001389 s = BGP_INPUT(peer);
1390 start = stream_get_getp(s);
1391
1392 /* safe to read statically sized header? */
1393#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001394#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001395 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001396 {
1397 zlog_info ("%s: %s sent invalid length, %lu",
1398 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001399 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001400 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001401
paul718e3742002-12-13 20:15:29 +00001402 /* Load AFI, SAFI. */
1403 afi = stream_getw (s);
1404 safi = stream_getc (s);
1405
1406 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001407 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001408
Paul Jakma03292802008-06-07 20:37:10 +00001409 if (LEN_LEFT < attre->mp_nexthop_len)
1410 {
1411 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1412 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001413 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001414 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001415
paul718e3742002-12-13 20:15:29 +00001416 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001417 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001418 {
1419 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001420 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001421 /* Probably needed for RFC 2283 */
1422 if (attr->nexthop.s_addr == 0)
1423 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001424 break;
1425 case 12:
1426 {
1427 u_int32_t rd_high;
1428 u_int32_t rd_low;
1429
1430 rd_high = stream_getl (s);
1431 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001432 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001433 }
1434 break;
1435#ifdef HAVE_IPV6
1436 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001437 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001438 break;
1439 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001440 stream_get (&attre->mp_nexthop_global, s, 16);
1441 stream_get (&attre->mp_nexthop_local, s, 16);
1442 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001443 {
1444 char buf1[INET6_ADDRSTRLEN];
1445 char buf2[INET6_ADDRSTRLEN];
1446
1447 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001448 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 +00001449 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001450 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001451 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001452 buf2, INET6_ADDRSTRLEN));
1453
Paul Jakmafb982c22007-05-04 20:15:47 +00001454 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001455 }
1456 break;
1457#endif /* HAVE_IPV6 */
1458 default:
Paul Jakma03292802008-06-07 20:37:10 +00001459 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1460 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001461 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001462 }
1463
Paul Jakma03292802008-06-07 20:37:10 +00001464 if (!LEN_LEFT)
1465 {
1466 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1467 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001468 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001469 }
paul718e3742002-12-13 20:15:29 +00001470
Paul Jakma6e4ab122007-04-10 19:36:48 +00001471 {
1472 u_char val;
1473 if ((val = stream_getc (s)))
1474 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1475 peer->host, val);
1476 }
1477
1478 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001479 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001480 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001481 {
1482 zlog_info ("%s: (%s) Failed to read NLRI",
1483 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001484 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001485 }
paul718e3742002-12-13 20:15:29 +00001486
1487 if (safi != BGP_SAFI_VPNV4)
1488 {
1489 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001490 if (ret < 0)
1491 {
1492 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1493 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001494 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001495 }
paul718e3742002-12-13 20:15:29 +00001496 }
1497
1498 mp_update->afi = afi;
1499 mp_update->safi = safi;
1500 mp_update->nlri = stream_pnt (s);
1501 mp_update->length = nlri_len;
1502
paul9985f832005-02-09 15:51:56 +00001503 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001504
Paul Jakmab881c702010-11-23 16:35:42 +00001505 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001506#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001507}
1508
1509/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001510int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001511bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001512 struct bgp_nlri *mp_withdraw)
1513{
1514 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001515 afi_t afi;
1516 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001517 u_int16_t withdraw_len;
1518 int ret;
1519
1520 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001521
1522#define BGP_MP_UNREACH_MIN_SIZE 3
1523 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001524 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001525
paul718e3742002-12-13 20:15:29 +00001526 afi = stream_getw (s);
1527 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001528
1529 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001530
1531 if (safi != BGP_SAFI_VPNV4)
1532 {
1533 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1534 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001535 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001536 }
1537
1538 mp_withdraw->afi = afi;
1539 mp_withdraw->safi = safi;
1540 mp_withdraw->nlri = stream_pnt (s);
1541 mp_withdraw->length = withdraw_len;
1542
paul9985f832005-02-09 15:51:56 +00001543 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001544
Paul Jakmab881c702010-11-23 16:35:42 +00001545 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001546}
1547
1548/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001549static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001550bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001551 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001552{
Paul Jakmab881c702010-11-23 16:35:42 +00001553 bgp_size_t total
1554 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1555
paul718e3742002-12-13 20:15:29 +00001556 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001557 {
1558 if (attr->extra)
1559 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001560 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001561 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001562 }
Paul Jakma0c466382010-12-05 17:17:26 +00001563
1564 (bgp_attr_extra_get (attr))->ecommunity =
1565 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1566 /* XXX: fix ecommunity_parse to use stream API */
1567 stream_forward_getp (peer->ibuf, length);
1568
1569 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001570 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1571 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1572 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001573
paul718e3742002-12-13 20:15:29 +00001574 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1575
Paul Jakmab881c702010-11-23 16:35:42 +00001576 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001577}
1578
1579/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001580static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001581bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1582 u_char type, bgp_size_t length, u_char *startp)
1583{
1584 bgp_size_t total;
1585 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001586 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001587
hassof4184462005-02-01 20:13:16 +00001588 if (BGP_DEBUG (normal, NORMAL))
1589 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1590 peer->host, type, length);
1591
paul718e3742002-12-13 20:15:29 +00001592 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001593 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001594 "Unknown attribute type %d length %d is received", type, length);
1595
1596 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001597 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001598
1599 /* Adjest total length to include type and length. */
1600 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1601
1602 /* If any of the mandatory well-known attributes are not recognized,
1603 then the Error Subcode is set to Unrecognized Well-known
1604 Attribute. The Data field contains the unrecognized attribute
1605 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001606 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001607 {
Paul Jakmab881c702010-11-23 16:35:42 +00001608 return bgp_attr_malformed (peer, type, flag,
1609 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1610 startp, total);
paul718e3742002-12-13 20:15:29 +00001611 }
1612
1613 /* Unrecognized non-transitive optional attributes must be quietly
1614 ignored and not passed along to other BGP peers. */
1615 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001616 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001617
1618 /* If a path with recognized transitive optional attribute is
1619 accepted and passed along to other BGP peers and the Partial bit
1620 in the Attribute Flags octet is set to 1 by some previous AS, it
1621 is not set back to 0 by the current AS. */
1622 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1623
1624 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001625 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001626 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001627
Paul Jakmafb982c22007-05-04 20:15:47 +00001628 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001629
1630 if (transit->val)
1631 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1632 transit->length + total);
1633 else
1634 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1635
1636 memcpy (transit->val + transit->length, startp, total);
1637 transit->length += total;
1638
Paul Jakmab881c702010-11-23 16:35:42 +00001639 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001640}
1641
1642/* Read attribute of update packet. This function is called from
1643 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001644bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001645bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1646 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1647{
1648 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001649 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001650 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001651 bgp_size_t length;
1652 u_char *startp, *endp;
1653 u_char *attr_endp;
1654 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001655 /* we need the as4_path only until we have synthesized the as_path with it */
1656 /* same goes for as4_aggregator */
1657 struct aspath *as4_path = NULL;
1658 as_t as4_aggregator = 0;
1659 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001660
1661 /* Initialize bitmap. */
1662 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1663
1664 /* End pointer of BGP attribute. */
1665 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001666
paul718e3742002-12-13 20:15:29 +00001667 /* Get attributes to the end of attribute length. */
1668 while (BGP_INPUT_PNT (peer) < endp)
1669 {
1670 /* Check remaining length check.*/
1671 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1672 {
gdtc29fdba2004-12-09 14:46:46 +00001673 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001674 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001675 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001676 peer->host,
1677 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001678
1679 bgp_notify_send (peer,
1680 BGP_NOTIFY_UPDATE_ERR,
1681 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001682 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001683 }
1684
1685 /* Fetch attribute flag and type. */
1686 startp = BGP_INPUT_PNT (peer);
1687 flag = stream_getc (BGP_INPUT (peer));
1688 type = stream_getc (BGP_INPUT (peer));
1689
Paul Jakma370b64a2007-12-22 16:49:52 +00001690 /* Check whether Extended-Length applies and is in bounds */
1691 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1692 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1693 {
1694 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001695 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001696 peer->host,
1697 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1698
1699 bgp_notify_send (peer,
1700 BGP_NOTIFY_UPDATE_ERR,
1701 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001702 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001703 }
1704
paul718e3742002-12-13 20:15:29 +00001705 /* Check extended attribue length bit. */
1706 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1707 length = stream_getw (BGP_INPUT (peer));
1708 else
1709 length = stream_getc (BGP_INPUT (peer));
1710
1711 /* If any attribute appears more than once in the UPDATE
1712 message, then the Error Subcode is set to Malformed Attribute
1713 List. */
1714
1715 if (CHECK_BITMAP (seen, type))
1716 {
1717 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001718 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001719 peer->host, type);
1720
1721 bgp_notify_send (peer,
1722 BGP_NOTIFY_UPDATE_ERR,
1723 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001724 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001725 }
1726
1727 /* Set type to bitmap to check duplicate attribute. `type' is
1728 unsigned char so it never overflow bitmap range. */
1729
1730 SET_BITMAP (seen, type);
1731
1732 /* Overflow check. */
1733 attr_endp = BGP_INPUT_PNT (peer) + length;
1734
1735 if (attr_endp > endp)
1736 {
1737 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001738 "%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 +00001739 bgp_notify_send (peer,
1740 BGP_NOTIFY_UPDATE_ERR,
1741 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001742 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001743 }
1744
1745 /* OK check attribute and store it's value. */
1746 switch (type)
1747 {
1748 case BGP_ATTR_ORIGIN:
1749 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1750 break;
1751 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001752 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001753 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001754 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001755 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001756 break;
paul718e3742002-12-13 20:15:29 +00001757 case BGP_ATTR_NEXT_HOP:
1758 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1759 break;
1760 case BGP_ATTR_MULTI_EXIT_DISC:
1761 ret = bgp_attr_med (peer, length, attr, flag, startp);
1762 break;
1763 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001764 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001765 break;
1766 case BGP_ATTR_ATOMIC_AGGREGATE:
1767 ret = bgp_attr_atomic (peer, length, attr, flag);
1768 break;
1769 case BGP_ATTR_AGGREGATOR:
1770 ret = bgp_attr_aggregator (peer, length, attr, flag);
1771 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001772 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001773 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1774 &as4_aggregator,
1775 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001776 break;
paul718e3742002-12-13 20:15:29 +00001777 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001778 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001779 break;
1780 case BGP_ATTR_ORIGINATOR_ID:
1781 ret = bgp_attr_originator_id (peer, length, attr, flag);
1782 break;
1783 case BGP_ATTR_CLUSTER_LIST:
1784 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1785 break;
1786 case BGP_ATTR_MP_REACH_NLRI:
1787 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1788 break;
1789 case BGP_ATTR_MP_UNREACH_NLRI:
1790 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1791 break;
1792 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001793 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001794 break;
1795 default:
1796 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1797 break;
1798 }
Paul Jakmab881c702010-11-23 16:35:42 +00001799
1800 /* If hard error occured immediately return to the caller. */
1801 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001802 {
1803 zlog (peer->log, LOG_WARNING,
1804 "%s: Attribute %s, parse error",
1805 peer->host,
1806 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001807 bgp_notify_send (peer,
1808 BGP_NOTIFY_UPDATE_ERR,
1809 BGP_NOTIFY_UPDATE_MAL_ATTR);
1810 if (as4_path)
1811 aspath_unintern (&as4_path);
1812 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001813 }
Paul Jakmab881c702010-11-23 16:35:42 +00001814 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1815 {
1816
1817 zlog (peer->log, LOG_WARNING,
1818 "%s: Attribute %s, parse error - treating as withdrawal",
1819 peer->host,
1820 LOOKUP (attr_str, type));
1821 if (as4_path)
1822 aspath_unintern (&as4_path);
1823 return ret;
1824 }
1825
paul718e3742002-12-13 20:15:29 +00001826 /* Check the fetched length. */
1827 if (BGP_INPUT_PNT (peer) != attr_endp)
1828 {
1829 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001830 "%s: BGP attribute %s, fetch error",
1831 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001832 bgp_notify_send (peer,
1833 BGP_NOTIFY_UPDATE_ERR,
1834 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001835 if (as4_path)
1836 aspath_unintern (&as4_path);
1837 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001838 }
1839 }
1840
1841 /* Check final read pointer is same as end pointer. */
1842 if (BGP_INPUT_PNT (peer) != endp)
1843 {
1844 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001845 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001846 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001847 bgp_notify_send (peer,
1848 BGP_NOTIFY_UPDATE_ERR,
1849 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001850 if (as4_path)
1851 aspath_unintern (&as4_path);
1852 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001853 }
1854
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001855 /*
1856 * At this place we can see whether we got AS4_PATH and/or
1857 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1858 * We can not do this before we've read all attributes because
1859 * the as4 handling does not say whether AS4_PATH has to be sent
1860 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1861 * in relationship to AGGREGATOR.
1862 * So, to be defensive, we are not relying on any order and read
1863 * all attributes first, including these 32bit ones, and now,
1864 * afterwards, we look what and if something is to be done for as4.
1865 */
Paul Jakmab881c702010-11-23 16:35:42 +00001866 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001867 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001868 {
1869 if (as4_path)
1870 aspath_unintern (&as4_path);
1871 return BGP_ATTR_PARSE_ERROR;
1872 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001873
1874 /* At this stage, we have done all fiddling with as4, and the
1875 * resulting info is in attr->aggregator resp. attr->aspath
1876 * so we can chuck as4_aggregator and as4_path alltogether in
1877 * order to save memory
1878 */
Paul Jakmab881c702010-11-23 16:35:42 +00001879 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001880 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001881 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001882 /* The flag that we got this is still there, but that does not
1883 * do any trouble
1884 */
1885 }
1886 /*
1887 * The "rest" of the code does nothing with as4_aggregator.
1888 * there is no memory attached specifically which is not part
1889 * of the attr.
1890 * so ignoring just means do nothing.
1891 */
1892 /*
1893 * Finally do the checks on the aspath we did not do yet
1894 * because we waited for a potentially synthesized aspath.
1895 */
Paul Jakmab881c702010-11-23 16:35:42 +00001896 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001897 {
Paul Jakmab881c702010-11-23 16:35:42 +00001898 ret = bgp_attr_aspath_check (peer, attr, flag);
1899 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001900 return ret;
1901 }
1902
paul718e3742002-12-13 20:15:29 +00001903 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001904 if (attr->extra && attr->extra->transit)
1905 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001906
Paul Jakmab881c702010-11-23 16:35:42 +00001907 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001908}
1909
1910/* Well-known attribute check. */
1911int
1912bgp_attr_check (struct peer *peer, struct attr *attr)
1913{
1914 u_char type = 0;
1915
1916 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1917 type = BGP_ATTR_ORIGIN;
1918
1919 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1920 type = BGP_ATTR_AS_PATH;
1921
1922 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1923 type = BGP_ATTR_NEXT_HOP;
1924
1925 if (peer_sort (peer) == BGP_PEER_IBGP
1926 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1927 type = BGP_ATTR_LOCAL_PREF;
1928
1929 if (type)
1930 {
1931 zlog (peer->log, LOG_WARNING,
1932 "%s Missing well-known attribute %d.",
1933 peer->host, type);
1934 bgp_notify_send_with_data (peer,
1935 BGP_NOTIFY_UPDATE_ERR,
1936 BGP_NOTIFY_UPDATE_MISS_ATTR,
1937 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00001938 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001939 }
Paul Jakmab881c702010-11-23 16:35:42 +00001940 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001941}
1942
1943int stream_put_prefix (struct stream *, struct prefix *);
1944
1945/* Make attribute packet. */
1946bgp_size_t
1947bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1948 struct stream *s, struct attr *attr, struct prefix *p,
1949 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001950 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001951{
paulfe69a502005-09-10 16:55:02 +00001952 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001953 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001954 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001955 int send_as4_path = 0;
1956 int send_as4_aggregator = 0;
1957 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001958
1959 if (! bgp)
1960 bgp = bgp_get_default ();
1961
1962 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001963 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001964
1965 /* Origin attribute. */
1966 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1967 stream_putc (s, BGP_ATTR_ORIGIN);
1968 stream_putc (s, 1);
1969 stream_putc (s, attr->origin);
1970
1971 /* AS path attribute. */
1972
1973 /* If remote-peer is EBGP */
1974 if (peer_sort (peer) == BGP_PEER_EBGP
1975 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001976 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001977 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001978 {
1979 aspath = aspath_dup (attr->aspath);
1980
1981 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1982 {
1983 /* Strip the confed info, and then stuff our path CONFED_ID
1984 on the front */
1985 aspath = aspath_delete_confed_seq (aspath);
1986 aspath = aspath_add_seq (aspath, bgp->confed_id);
1987 }
1988 else
1989 {
1990 aspath = aspath_add_seq (aspath, peer->local_as);
1991 if (peer->change_local_as)
1992 aspath = aspath_add_seq (aspath, peer->change_local_as);
1993 }
1994 }
1995 else if (peer_sort (peer) == BGP_PEER_CONFED)
1996 {
1997 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1998 aspath = aspath_dup (attr->aspath);
1999 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2000 }
2001 else
2002 aspath = attr->aspath;
2003
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002004 /* If peer is not AS4 capable, then:
2005 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2006 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2007 * types are in it (i.e. exclude them if they are there)
2008 * AND do this only if there is at least one asnum > 65535 in the path!
2009 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2010 * all ASnums > 65535 to BGP_AS_TRANS
2011 */
paul718e3742002-12-13 20:15:29 +00002012
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002013 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2014 stream_putc (s, BGP_ATTR_AS_PATH);
2015 aspath_sizep = stream_get_endp (s);
2016 stream_putw (s, 0);
2017 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2018
2019 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2020 * in the path
2021 */
2022 if (!use32bit && aspath_has_as4 (aspath))
2023 send_as4_path = 1; /* we'll do this later, at the correct place */
2024
paul718e3742002-12-13 20:15:29 +00002025 /* Nexthop attribute. */
2026 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2027 {
2028 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2029 stream_putc (s, BGP_ATTR_NEXT_HOP);
2030 stream_putc (s, 4);
2031 if (safi == SAFI_MPLS_VPN)
2032 {
2033 if (attr->nexthop.s_addr == 0)
2034 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2035 else
2036 stream_put_ipv4 (s, attr->nexthop.s_addr);
2037 }
2038 else
2039 stream_put_ipv4 (s, attr->nexthop.s_addr);
2040 }
2041
2042 /* MED attribute. */
2043 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2044 {
2045 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2046 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2047 stream_putc (s, 4);
2048 stream_putl (s, attr->med);
2049 }
2050
2051 /* Local preference. */
2052 if (peer_sort (peer) == BGP_PEER_IBGP ||
2053 peer_sort (peer) == BGP_PEER_CONFED)
2054 {
2055 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2056 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2057 stream_putc (s, 4);
2058 stream_putl (s, attr->local_pref);
2059 }
2060
2061 /* Atomic aggregate. */
2062 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2063 {
2064 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2065 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2066 stream_putc (s, 0);
2067 }
2068
2069 /* Aggregator. */
2070 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2071 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002072 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002073
2074 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002075 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2076 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002077
2078 if (use32bit)
2079 {
2080 /* AS4 capable peer */
2081 stream_putc (s, 8);
2082 stream_putl (s, attr->extra->aggregator_as);
2083 }
2084 else
2085 {
2086 /* 2-byte AS peer */
2087 stream_putc (s, 6);
2088
2089 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2090 if ( attr->extra->aggregator_as > 65535 )
2091 {
2092 stream_putw (s, BGP_AS_TRANS);
2093
2094 /* we have to send AS4_AGGREGATOR, too.
2095 * we'll do that later in order to send attributes in ascending
2096 * order.
2097 */
2098 send_as4_aggregator = 1;
2099 }
2100 else
2101 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2102 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002103 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002104 }
2105
2106 /* Community attribute. */
2107 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2108 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2109 {
2110 if (attr->community->size * 4 > 255)
2111 {
2112 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2113 stream_putc (s, BGP_ATTR_COMMUNITIES);
2114 stream_putw (s, attr->community->size * 4);
2115 }
2116 else
2117 {
2118 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2119 stream_putc (s, BGP_ATTR_COMMUNITIES);
2120 stream_putc (s, attr->community->size * 4);
2121 }
2122 stream_put (s, attr->community->val, attr->community->size * 4);
2123 }
2124
2125 /* Route Reflector. */
2126 if (peer_sort (peer) == BGP_PEER_IBGP
2127 && from
2128 && peer_sort (from) == BGP_PEER_IBGP)
2129 {
2130 /* Originator ID. */
2131 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2132 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2133 stream_putc (s, 4);
2134
2135 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002136 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002137 else
2138 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002139
2140 /* Cluster list. */
2141 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2142 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2143
Paul Jakma9eda90c2007-08-30 13:36:17 +00002144 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002145 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002147 /* If this peer configuration's parent BGP has cluster_id. */
2148 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2149 stream_put_in_addr (s, &bgp->cluster_id);
2150 else
2151 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002152 stream_put (s, attr->extra->cluster->list,
2153 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002154 }
2155 else
2156 {
2157 stream_putc (s, 4);
2158 /* If this peer configuration's parent BGP has cluster_id. */
2159 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2160 stream_put_in_addr (s, &bgp->cluster_id);
2161 else
2162 stream_put_in_addr (s, &bgp->router_id);
2163 }
2164 }
2165
2166#ifdef HAVE_IPV6
2167 /* If p is IPv6 address put it into attribute. */
2168 if (p->family == AF_INET6)
2169 {
2170 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002171 struct attr_extra *attre = attr->extra;
2172
2173 assert (attr->extra);
2174
paul718e3742002-12-13 20:15:29 +00002175 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_IP6); /* AFI */
2180 stream_putc (s, safi); /* SAFI */
2181
Paul Jakmafb982c22007-05-04 20:15:47 +00002182 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002183
Paul Jakmafb982c22007-05-04 20:15:47 +00002184 if (attre->mp_nexthop_len == 16)
2185 stream_put (s, &attre->mp_nexthop_global, 16);
2186 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002187 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002188 stream_put (s, &attre->mp_nexthop_global, 16);
2189 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002190 }
2191
2192 /* SNPA */
2193 stream_putc (s, 0);
2194
paul718e3742002-12-13 20:15:29 +00002195 /* Prefix write. */
2196 stream_put_prefix (s, p);
2197
2198 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002199 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002200 }
2201#endif /* HAVE_IPV6 */
2202
2203 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2204 {
2205 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002206
2207 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2208 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002209 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002210 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002211 stream_putw (s, AFI_IP); /* AFI */
2212 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2213
2214 stream_putc (s, 4);
2215 stream_put_ipv4 (s, attr->nexthop.s_addr);
2216
2217 /* SNPA */
2218 stream_putc (s, 0);
2219
paul718e3742002-12-13 20:15:29 +00002220 /* Prefix write. */
2221 stream_put_prefix (s, p);
2222
2223 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002224 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002225 }
2226
2227 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2228 {
2229 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002230
2231 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2232 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002233 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002234 stream_putc (s, 0); /* Length of this attribute. */
2235 stream_putw (s, AFI_IP); /* AFI */
2236 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2237
2238 stream_putc (s, 12);
2239 stream_putl (s, 0);
2240 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002241 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002242
2243 /* SNPA */
2244 stream_putc (s, 0);
2245
paul718e3742002-12-13 20:15:29 +00002246 /* Tag, RD, Prefix write. */
2247 stream_putc (s, p->prefixlen + 88);
2248 stream_put (s, tag, 3);
2249 stream_put (s, prd->val, 8);
2250 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2251
2252 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002253 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002254 }
2255
2256 /* Extended Communities attribute. */
2257 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2258 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2259 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002260 struct attr_extra *attre = attr->extra;
2261
2262 assert (attre);
2263
2264 if (peer_sort (peer) == BGP_PEER_IBGP
2265 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002266 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002267 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002268 {
2269 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2270 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002271 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002272 }
2273 else
2274 {
2275 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2276 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002277 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002278 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002279 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002280 }
2281 else
2282 {
paul5228ad22004-06-04 17:58:18 +00002283 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002284 int tbit;
2285 int ecom_tr_size = 0;
2286 int i;
2287
Paul Jakmafb982c22007-05-04 20:15:47 +00002288 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002289 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002290 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002291 tbit = *pnt;
2292
2293 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2294 continue;
2295
2296 ecom_tr_size++;
2297 }
2298
2299 if (ecom_tr_size)
2300 {
2301 if (ecom_tr_size * 8 > 255)
2302 {
2303 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2304 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2305 stream_putw (s, ecom_tr_size * 8);
2306 }
2307 else
2308 {
2309 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2310 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2311 stream_putc (s, ecom_tr_size * 8);
2312 }
2313
Paul Jakmafb982c22007-05-04 20:15:47 +00002314 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002315 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002316 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002317 tbit = *pnt;
2318
2319 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2320 continue;
2321
2322 stream_put (s, pnt, 8);
2323 }
2324 }
paul718e3742002-12-13 20:15:29 +00002325 }
paul718e3742002-12-13 20:15:29 +00002326 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002327
2328 if ( send_as4_path )
2329 {
2330 /* If the peer is NOT As4 capable, AND */
2331 /* there are ASnums > 65535 in path THEN
2332 * give out AS4_PATH */
2333
2334 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2335 * path segments!
2336 * Hm, I wonder... confederation things *should* only be at
2337 * the beginning of an aspath, right? Then we should use
2338 * aspath_delete_confed_seq for this, because it is already
2339 * there! (JK)
2340 * Folks, talk to me: what is reasonable here!?
2341 */
2342 aspath = aspath_delete_confed_seq (aspath);
2343
2344 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2345 stream_putc (s, BGP_ATTR_AS4_PATH);
2346 aspath_sizep = stream_get_endp (s);
2347 stream_putw (s, 0);
2348 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2349 }
2350
2351 if (aspath != attr->aspath)
2352 aspath_free (aspath);
2353
2354 if ( send_as4_aggregator )
2355 {
2356 assert (attr->extra);
2357
2358 /* send AS4_AGGREGATOR, at this place */
2359 /* this section of code moved here in order to ensure the correct
2360 * *ascending* order of attributes
2361 */
2362 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2363 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2364 stream_putc (s, 8);
2365 stream_putl (s, attr->extra->aggregator_as);
2366 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2367 }
Paul Jakma41367172007-08-06 15:24:51 +00002368
paul718e3742002-12-13 20:15:29 +00002369 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002370 if (attr->extra && attr->extra->transit)
2371 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002372
2373 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002374 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002375}
2376
2377bgp_size_t
2378bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2379 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002380 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002381{
2382 unsigned long cp;
2383 unsigned long attrlen_pnt;
2384 bgp_size_t size;
2385
paul9985f832005-02-09 15:51:56 +00002386 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002387
2388 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2389 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2390
paul9985f832005-02-09 15:51:56 +00002391 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002392 stream_putc (s, 0); /* Length of this attribute. */
2393
2394 stream_putw (s, family2afi (p->family));
2395
2396 if (safi == SAFI_MPLS_VPN)
2397 {
2398 /* SAFI */
2399 stream_putc (s, BGP_SAFI_VPNV4);
2400
2401 /* prefix. */
2402 stream_putc (s, p->prefixlen + 88);
2403 stream_put (s, tag, 3);
2404 stream_put (s, prd->val, 8);
2405 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2406 }
2407 else
2408 {
2409 /* SAFI */
2410 stream_putc (s, safi);
2411
2412 /* prefix */
2413 stream_put_prefix (s, p);
2414 }
2415
2416 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002417 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002418 stream_putc_at (s, attrlen_pnt, size);
2419
paul9985f832005-02-09 15:51:56 +00002420 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002421}
2422
2423/* Initialization of attribute. */
2424void
paulfe69a502005-09-10 16:55:02 +00002425bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002426{
paul718e3742002-12-13 20:15:29 +00002427 aspath_init ();
2428 attrhash_init ();
2429 community_init ();
2430 ecommunity_init ();
2431 cluster_init ();
2432 transit_init ();
2433}
2434
Chris Caputo228da422009-07-18 05:44:03 +00002435void
2436bgp_attr_finish (void)
2437{
2438 aspath_finish ();
2439 attrhash_finish ();
2440 community_finish ();
2441 ecommunity_finish ();
2442 cluster_finish ();
2443 transit_finish ();
2444}
2445
paul718e3742002-12-13 20:15:29 +00002446/* Make attribute packet. */
2447void
paula3845922003-10-18 01:30:50 +00002448bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2449 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002450{
2451 unsigned long cp;
2452 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002453 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002454 struct aspath *aspath;
2455
2456 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002457 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002458
2459 /* Place holder of length. */
2460 stream_putw (s, 0);
2461
2462 /* Origin attribute. */
2463 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2464 stream_putc (s, BGP_ATTR_ORIGIN);
2465 stream_putc (s, 1);
2466 stream_putc (s, attr->origin);
2467
2468 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002469
2470 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2471 stream_putc (s, BGP_ATTR_AS_PATH);
2472 aspath_lenp = stream_get_endp (s);
2473 stream_putw (s, 0);
2474
2475 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002476
2477 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002478 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2479 if(prefix != NULL
2480#ifdef HAVE_IPV6
2481 && prefix->family != AF_INET6
2482#endif /* HAVE_IPV6 */
2483 )
2484 {
2485 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2486 stream_putc (s, BGP_ATTR_NEXT_HOP);
2487 stream_putc (s, 4);
2488 stream_put_ipv4 (s, attr->nexthop.s_addr);
2489 }
paul718e3742002-12-13 20:15:29 +00002490
2491 /* MED attribute. */
2492 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2493 {
2494 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2495 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2496 stream_putc (s, 4);
2497 stream_putl (s, attr->med);
2498 }
2499
2500 /* Local preference. */
2501 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2502 {
2503 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2504 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2505 stream_putc (s, 4);
2506 stream_putl (s, attr->local_pref);
2507 }
2508
2509 /* Atomic aggregate. */
2510 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2511 {
2512 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2513 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2514 stream_putc (s, 0);
2515 }
2516
2517 /* Aggregator. */
2518 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2519 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002520 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002521 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2522 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002523 stream_putc (s, 8);
2524 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002525 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002526 }
2527
2528 /* Community attribute. */
2529 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2530 {
2531 if (attr->community->size * 4 > 255)
2532 {
2533 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2534 stream_putc (s, BGP_ATTR_COMMUNITIES);
2535 stream_putw (s, attr->community->size * 4);
2536 }
2537 else
2538 {
2539 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2540 stream_putc (s, BGP_ATTR_COMMUNITIES);
2541 stream_putc (s, attr->community->size * 4);
2542 }
2543 stream_put (s, attr->community->val, attr->community->size * 4);
2544 }
2545
paula3845922003-10-18 01:30:50 +00002546#ifdef HAVE_IPV6
2547 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002548 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2549 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002550 {
2551 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002552 struct attr_extra *attre = attr->extra;
2553
paula3845922003-10-18 01:30:50 +00002554 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2555 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002556 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002557
2558 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002559 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002560 stream_putw(s, AFI_IP6); /* AFI */
2561 stream_putc(s, SAFI_UNICAST); /* SAFI */
2562
2563 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002564 stream_putc(s, attre->mp_nexthop_len);
2565 stream_put(s, &attre->mp_nexthop_global, 16);
2566 if (attre->mp_nexthop_len == 32)
2567 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002568
2569 /* SNPA */
2570 stream_putc(s, 0);
2571
2572 /* Prefix */
2573 stream_put_prefix(s, prefix);
2574
2575 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002576 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002577 }
2578#endif /* HAVE_IPV6 */
2579
paul718e3742002-12-13 20:15:29 +00002580 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002581 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002582 stream_putw_at (s, cp, len);
2583}