blob: a60bb8e5e24511cc656d5110c34ff4cafe8bed01 [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" },
Denis Ovsienkof8627ff2011-10-10 16:52:20 +040054 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
paul718e3742002-12-13 20:15:29 +000055 { 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). */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400776 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400777 {
778 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
779 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
780 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
781 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
782 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
783 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
784 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
785 }
paul718e3742002-12-13 20:15:29 +0000786
787 /* If any recognized attribute has Attribute Length that conflicts
788 with the expected length (based on the attribute type code), then
789 the Error Subcode is set to Attribute Length Error. The Data
790 field contains the erroneous attribute (type, length and
791 value). */
792 if (length != 1)
793 {
794 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
795 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000796 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
797 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
798 startp, total);
paul718e3742002-12-13 20:15:29 +0000799 }
800
801 /* Fetch origin attribute. */
802 attr->origin = stream_getc (BGP_INPUT (peer));
803
804 /* If the ORIGIN attribute has an undefined value, then the Error
805 Subcode is set to Invalid Origin Attribute. The Data field
806 contains the unrecognized attribute (type, length and value). */
807 if ((attr->origin != BGP_ORIGIN_IGP)
808 && (attr->origin != BGP_ORIGIN_EGP)
809 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
810 {
811 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
812 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000813 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
814 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
815 startp, total);
paul718e3742002-12-13 20:15:29 +0000816 }
817
818 /* Set oring attribute flag. */
819 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
820
821 return 0;
822}
Paul Jakmaab005292010-11-27 22:48:34 +0000823
824/* Parse AS path information. This function is wrapper of
825 aspath_parse. */
826static int
paul718e3742002-12-13 20:15:29 +0000827bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000828 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000829{
Paul Jakmaab005292010-11-27 22:48:34 +0000830 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000831
Paul Jakmaab005292010-11-27 22:48:34 +0000832 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000833
Paul Jakmaab005292010-11-27 22:48:34 +0000834 /* Flag check. */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400835 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
836 {
837 zlog (peer->log, LOG_ERR,
838 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
839 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
840 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
841 startp, total);
842 }
843
Paul Jakmaab005292010-11-27 22:48:34 +0000844 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
845 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000846 {
847 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000848 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000849 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
850 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
851 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400852 }
Paul Jakmaab005292010-11-27 22:48:34 +0000853
854 /*
855 * peer with AS4 => will get 4Byte ASnums
856 * otherwise, will get 16 Bit
857 */
858 attr->aspath = aspath_parse (peer->ibuf, length,
859 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
860
861 /* In case of IBGP, length will be zero. */
862 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000863 {
Paul Jakmab881c702010-11-23 16:35:42 +0000864 zlog (peer->log, LOG_ERR,
865 "Malformed AS path from %s, length is %d",
866 peer->host, length);
867 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
868 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
869 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000870 }
Chris Hallcddb8112010-08-09 22:31:37 +0400871
Paul Jakmaab005292010-11-27 22:48:34 +0000872 /* Set aspath attribute flag. */
873 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000874
Paul Jakmab881c702010-11-23 16:35:42 +0000875 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000876}
877
Paul Jakmab881c702010-11-23 16:35:42 +0000878static bgp_attr_parse_ret_t
879bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000880{
881 /* These checks were part of bgp_attr_aspath, but with
882 * as4 we should to check aspath things when
883 * aspath synthesizing with as4_path has already taken place.
884 * Otherwise we check ASPATH and use the synthesized thing, and that is
885 * not right.
886 * So do the checks later, i.e. here
887 */
888 struct bgp *bgp = peer->bgp;
889 struct aspath *aspath;
890
paul718e3742002-12-13 20:15:29 +0000891 bgp = peer->bgp;
892
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300893 /* Confederation sanity check. */
894 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
895 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
896 {
897 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000898 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
899 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
900 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300901 }
902
paul718e3742002-12-13 20:15:29 +0000903 /* First AS check for EBGP. */
904 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
905 {
906 if (peer_sort (peer) == BGP_PEER_EBGP
907 && ! aspath_firstas_check (attr->aspath, peer->as))
908 {
909 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400910 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000911 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
912 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
913 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000914 }
915 }
916
917 /* local-as prepend */
918 if (peer->change_local_as &&
919 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
920 {
921 aspath = aspath_dup (attr->aspath);
922 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000923 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000924 attr->aspath = aspath_intern (aspath);
925 }
926
Paul Jakmab881c702010-11-23 16:35:42 +0000927 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000928}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000929
Paul Jakmaab005292010-11-27 22:48:34 +0000930/* Parse AS4 path information. This function is another wrapper of
931 aspath_parse. */
932static int
Paul Jakmab881c702010-11-23 16:35:42 +0000933bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
934 struct attr *attr, u_char flag, u_char *startp,
935 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000936{
Paul Jakmab881c702010-11-23 16:35:42 +0000937 bgp_size_t total;
938
939 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
940
941 /* Flag check. */
942 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
943 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
944 {
945 zlog (peer->log, LOG_ERR,
946 "As4-Path attribute flag isn't optional/transitive %d", flag);
947 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
948 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
949 startp, total);
950 }
951
Paul Jakmaab005292010-11-27 22:48:34 +0000952 *as4_path = aspath_parse (peer->ibuf, length, 1);
953
Paul Jakmab881c702010-11-23 16:35:42 +0000954 /* In case of IBGP, length will be zero. */
955 if (!*as4_path)
956 {
957 zlog (peer->log, LOG_ERR,
958 "Malformed AS4 path from %s, length is %d",
959 peer->host, length);
960 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
961 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
962 NULL, 0);
963 }
964
Paul Jakmaab005292010-11-27 22:48:34 +0000965 /* Set aspath attribute flag. */
966 if (as4_path)
967 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
968
Paul Jakmab881c702010-11-23 16:35:42 +0000969 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000970}
971
paul718e3742002-12-13 20:15:29 +0000972/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000973static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000974bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
975 struct attr *attr, u_char flag, u_char *startp)
976{
977 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400978 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000979
980 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
981
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400982 /* Flags check. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400983 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400984 {
985 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
986 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
987 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
988 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
989 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
990 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
991 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
992 }
paul718e3742002-12-13 20:15:29 +0000993
994 /* Check nexthop attribute length. */
995 if (length != 4)
996 {
997 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
998 length);
999
Paul Jakmab881c702010-11-23 16:35:42 +00001000 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1001 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1002 startp, total);
paul718e3742002-12-13 20:15:29 +00001003 }
1004
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001005 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1006 attribute must result in a NOTIFICATION message (this is implemented below).
1007 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1008 logged locally (this is implemented somewhere else). The UPDATE message
1009 gets ignored in any of these cases. */
1010 nexthop_n = stream_get_ipv4 (peer->ibuf);
1011 nexthop_h = ntohl (nexthop_n);
1012 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1013 {
1014 char buf[INET_ADDRSTRLEN];
1015 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1016 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1017 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1018 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1019 startp, total);
1020 }
1021
1022 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001023 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1024
Paul Jakmab881c702010-11-23 16:35:42 +00001025 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001026}
1027
1028/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001029static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001030bgp_attr_med (struct peer *peer, bgp_size_t length,
1031 struct attr *attr, u_char flag, u_char *startp)
1032{
1033 bgp_size_t total;
1034
1035 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1036
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001037 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001038 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001039 {
1040 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1041 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1042 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1043 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1044 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1045 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001046 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1047 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1048 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001049 }
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001050
paul718e3742002-12-13 20:15:29 +00001051 /* Length check. */
1052 if (length != 4)
1053 {
1054 zlog (peer->log, LOG_ERR,
1055 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001056
1057 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1058 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1059 startp, total);
paul718e3742002-12-13 20:15:29 +00001060 }
1061
1062 attr->med = stream_getl (peer->ibuf);
1063
1064 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1065
Paul Jakmab881c702010-11-23 16:35:42 +00001066 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001067}
1068
1069/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001070static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001071bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001072 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001073{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001074 bgp_size_t total;
1075
1076 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1077 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001078 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001079 {
1080 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1081 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1082 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1083 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1084 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1085 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001086 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
1087 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1088 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001089 }
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001090 /* Length check. */
1091 if (length != 4)
1092 {
1093 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001094 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001095 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1096 startp, total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001097 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001098
paul718e3742002-12-13 20:15:29 +00001099 /* If it is contained in an UPDATE message that is received from an
1100 external peer, then this attribute MUST be ignored by the
1101 receiving speaker. */
1102 if (peer_sort (peer) == BGP_PEER_EBGP)
1103 {
paul9985f832005-02-09 15:51:56 +00001104 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001105 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001106 }
1107
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001108 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001109
1110 /* Set atomic aggregate flag. */
1111 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1112
Paul Jakmab881c702010-11-23 16:35:42 +00001113 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001114}
1115
1116/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001117static int
paul718e3742002-12-13 20:15:29 +00001118bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001119 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001120{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001121 bgp_size_t total;
1122
1123 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1124 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001125 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001126 {
1127 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1128 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1129 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1130 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1131 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1132 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001133 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1134 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1135 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001136 }
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001137
1138 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001139 if (length != 0)
1140 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001141 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001142 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1143 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001144 startp, total);
paul718e3742002-12-13 20:15:29 +00001145 }
1146
1147 /* Set atomic aggregate flag. */
1148 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1149
Paul Jakmab881c702010-11-23 16:35:42 +00001150 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001151}
1152
1153/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001154static int
paul718e3742002-12-13 20:15:29 +00001155bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001156 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001157{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001158 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001159 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001160 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001161
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001162 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001163 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001164 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001165 wantedlen = 8;
1166
1167 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001168 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001169 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001170 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1171 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001172 startp, total);
paul718e3742002-12-13 20:15:29 +00001173 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001174
1175 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1176 attre->aggregator_as = stream_getl (peer->ibuf);
1177 else
1178 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001179 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001180
1181 /* Set atomic aggregate flag. */
1182 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1183
Paul Jakmab881c702010-11-23 16:35:42 +00001184 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001185}
1186
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001187/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001188static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001189bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001190 struct attr *attr, u_char flag,
1191 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001192 struct in_addr *as4_aggregator_addr)
1193{
1194 if (length != 8)
1195 {
1196 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001197 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1198 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1199 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001200 }
1201 *as4_aggregator_as = stream_getl (peer->ibuf);
1202 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1203
1204 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1205
Paul Jakmab881c702010-11-23 16:35:42 +00001206 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001207}
1208
1209/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1210 */
Paul Jakmab881c702010-11-23 16:35:42 +00001211static bgp_attr_parse_ret_t
1212bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001213 struct aspath *as4_path, as_t as4_aggregator,
1214 struct in_addr *as4_aggregator_addr)
1215{
1216 int ignore_as4_path = 0;
1217 struct aspath *newpath;
1218 struct attr_extra *attre = attr->extra;
1219
Paul Jakmab881c702010-11-23 16:35:42 +00001220 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001221 {
1222 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1223 * if given.
1224 * It is worth a warning though, because the peer really
1225 * should not send them
1226 */
1227 if (BGP_DEBUG(as4, AS4))
1228 {
1229 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1230 zlog_debug ("[AS4] %s %s AS4_PATH",
1231 peer->host, "AS4 capable peer, yet it sent");
1232
1233 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1234 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1235 peer->host, "AS4 capable peer, yet it sent");
1236 }
1237
Paul Jakmab881c702010-11-23 16:35:42 +00001238 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001239 }
1240
Paul Jakmab881c702010-11-23 16:35:42 +00001241 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1242 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001243 {
1244 /* Hu? This is not supposed to happen at all!
1245 * got as4_path and no aspath,
1246 * This should already
1247 * have been handled by 'well known attributes missing'
1248 * But... yeah, paranoia
1249 * Take this as a "malformed attribute"
1250 */
1251 zlog (peer->log, LOG_ERR,
1252 "%s BGP not AS4 capable peer sent AS4_PATH but"
1253 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001254 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1255 BGP_NOTIFY_UPDATE_MAL_ATTR,
1256 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001257 }
1258
1259 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1260 * because that may override AS4_PATH
1261 */
1262 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1263 {
Paul Jakmab881c702010-11-23 16:35:42 +00001264 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001265 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001266 assert (attre);
1267
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001268 /* received both.
1269 * if the as_number in aggregator is not AS_TRANS,
1270 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1271 * and the Aggregator shall be taken as
1272 * info on the aggregating node, and the AS_PATH
1273 * shall be taken as the AS_PATH
1274 * otherwise
1275 * the Aggregator shall be ignored and the
1276 * AS4_AGGREGATOR shall be taken as the
1277 * Aggregating node and the AS_PATH is to be
1278 * constructed "as in all other cases"
1279 */
Paul Jakmab881c702010-11-23 16:35:42 +00001280 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001281 {
1282 /* ignore */
1283 if ( BGP_DEBUG(as4, AS4))
1284 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1285 " send AGGREGATOR != AS_TRANS and"
1286 " AS4_AGGREGATOR, so ignore"
1287 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1288 ignore_as4_path = 1;
1289 }
1290 else
1291 {
1292 /* "New_aggregator shall be taken as aggregator" */
1293 attre->aggregator_as = as4_aggregator;
1294 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1295 }
1296 }
1297 else
1298 {
1299 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1300 * That is bogus - but reading the conditions
1301 * we have to handle AS4_AGGREGATOR as if it were
1302 * AGGREGATOR in that case
1303 */
1304 if ( BGP_DEBUG(as4, AS4))
1305 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1306 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1307 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001308 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001309 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1310 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1311 }
1312 }
1313
1314 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001315 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001316 {
1317 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001318 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001319 attr->aspath = aspath_intern (newpath);
1320 }
Paul Jakmab881c702010-11-23 16:35:42 +00001321 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001322}
1323
paul718e3742002-12-13 20:15:29 +00001324/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001325static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001326bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001327 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001328{
Paul Jakmab881c702010-11-23 16:35:42 +00001329 bgp_size_t total
1330 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1331
paul718e3742002-12-13 20:15:29 +00001332 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001333 {
1334 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001335 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001336 }
Paul Jakma0c466382010-12-05 17:17:26 +00001337
1338 attr->community =
1339 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1340
1341 /* XXX: fix community_parse to use stream API and remove this */
1342 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001343
Paul Jakma0c466382010-12-05 17:17:26 +00001344 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001345 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1346 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1347 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001348
paul718e3742002-12-13 20:15:29 +00001349 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1350
Paul Jakmab881c702010-11-23 16:35:42 +00001351 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001352}
1353
1354/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001355static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001356bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienkod595b562011-09-30 15:08:54 +04001357 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001358{
Denis Ovsienkod595b562011-09-30 15:08:54 +04001359 bgp_size_t total;
1360
1361 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1362 /* Flag checks. */
1363 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1364 {
1365 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1366 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1367 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1368 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1369 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1370 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001371 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1372 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1373 startp, total);
Denis Ovsienkod595b562011-09-30 15:08:54 +04001374 }
1375 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001376 if (length != 4)
1377 {
1378 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1379
Paul Jakmab881c702010-11-23 16:35:42 +00001380 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1381 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1382 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001383 }
1384
Paul Jakmafb982c22007-05-04 20:15:47 +00001385 (bgp_attr_extra_get (attr))->originator_id.s_addr
1386 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001387
1388 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1389
Paul Jakmab881c702010-11-23 16:35:42 +00001390 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001391}
1392
1393/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001394static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001395bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienko0b830442011-09-30 15:12:17 +04001396 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001397{
Denis Ovsienko0b830442011-09-30 15:12:17 +04001398 bgp_size_t total;
1399
1400 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1401 /* Flag checks. */
1402 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1403 {
1404 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1405 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1406 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1407 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1408 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1409 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001410 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1411 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1412 startp, total);
Denis Ovsienko0b830442011-09-30 15:12:17 +04001413 }
paul718e3742002-12-13 20:15:29 +00001414 /* Check length. */
1415 if (length % 4)
1416 {
1417 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1418
Paul Jakmab881c702010-11-23 16:35:42 +00001419 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1420 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1421 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001422 }
1423
Paul Jakmafb982c22007-05-04 20:15:47 +00001424 (bgp_attr_extra_get (attr))->cluster
1425 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001426
1427 /* XXX: Fix cluster_parse to use stream API and then remove this */
1428 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001429
1430 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1431
Paul Jakmab881c702010-11-23 16:35:42 +00001432 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001433}
1434
1435/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001436int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001437bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1438 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001439{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001440 afi_t afi;
1441 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001442 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001443 size_t start;
paul718e3742002-12-13 20:15:29 +00001444 int ret;
1445 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001446 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001447 bgp_size_t total;
1448
1449 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1450 /* Flag checks. */
1451 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1452 {
1453 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1454 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1455 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1456 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1457 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1458 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001459 return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag,
1460 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1461 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001462 }
paul718e3742002-12-13 20:15:29 +00001463 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001464 s = BGP_INPUT(peer);
1465 start = stream_get_getp(s);
1466
1467 /* safe to read statically sized header? */
1468#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001469#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001470 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001471 {
1472 zlog_info ("%s: %s sent invalid length, %lu",
1473 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001474 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001475 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001476
paul718e3742002-12-13 20:15:29 +00001477 /* Load AFI, SAFI. */
1478 afi = stream_getw (s);
1479 safi = stream_getc (s);
1480
1481 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001482 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001483
Paul Jakma03292802008-06-07 20:37:10 +00001484 if (LEN_LEFT < attre->mp_nexthop_len)
1485 {
1486 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1487 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001488 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001489 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001490
paul718e3742002-12-13 20:15:29 +00001491 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001492 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001493 {
1494 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001495 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001496 /* Probably needed for RFC 2283 */
1497 if (attr->nexthop.s_addr == 0)
1498 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001499 break;
1500 case 12:
1501 {
1502 u_int32_t rd_high;
1503 u_int32_t rd_low;
1504
1505 rd_high = stream_getl (s);
1506 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001507 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001508 }
1509 break;
1510#ifdef HAVE_IPV6
1511 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001512 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001513 break;
1514 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001515 stream_get (&attre->mp_nexthop_global, s, 16);
1516 stream_get (&attre->mp_nexthop_local, s, 16);
1517 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001518 {
1519 char buf1[INET6_ADDRSTRLEN];
1520 char buf2[INET6_ADDRSTRLEN];
1521
1522 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001523 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 +00001524 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001525 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001526 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001527 buf2, INET6_ADDRSTRLEN));
1528
Paul Jakmafb982c22007-05-04 20:15:47 +00001529 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001530 }
1531 break;
1532#endif /* HAVE_IPV6 */
1533 default:
Paul Jakma03292802008-06-07 20:37:10 +00001534 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1535 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001536 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001537 }
1538
Paul Jakma03292802008-06-07 20:37:10 +00001539 if (!LEN_LEFT)
1540 {
1541 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1542 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001543 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001544 }
paul718e3742002-12-13 20:15:29 +00001545
Paul Jakma6e4ab122007-04-10 19:36:48 +00001546 {
1547 u_char val;
1548 if ((val = stream_getc (s)))
1549 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1550 peer->host, val);
1551 }
1552
1553 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001554 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001555 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001556 {
1557 zlog_info ("%s: (%s) Failed to read NLRI",
1558 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001559 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001560 }
paul718e3742002-12-13 20:15:29 +00001561
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001562 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001563 {
1564 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001565 if (ret < 0)
1566 {
1567 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1568 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001569 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001570 }
paul718e3742002-12-13 20:15:29 +00001571 }
1572
1573 mp_update->afi = afi;
1574 mp_update->safi = safi;
1575 mp_update->nlri = stream_pnt (s);
1576 mp_update->length = nlri_len;
1577
paul9985f832005-02-09 15:51:56 +00001578 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001579
Paul Jakmab881c702010-11-23 16:35:42 +00001580 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001581#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001582}
1583
1584/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001585int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001586bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1587 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001588 struct bgp_nlri *mp_withdraw)
1589{
1590 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001591 afi_t afi;
1592 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001593 u_int16_t withdraw_len;
1594 int ret;
Denis Ovsienko565b8282011-10-10 21:08:33 +04001595 bgp_size_t total;
1596
1597 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1598 /* Flag checks. */
1599 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1600 {
1601 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1602 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1603 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1604 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1605 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1606 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001607 return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag,
1608 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1609 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001610 }
paul718e3742002-12-13 20:15:29 +00001611
1612 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001613
1614#define BGP_MP_UNREACH_MIN_SIZE 3
1615 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001616 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001617
paul718e3742002-12-13 20:15:29 +00001618 afi = stream_getw (s);
1619 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001620
1621 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001622
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001623 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001624 {
1625 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1626 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001627 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001628 }
1629
1630 mp_withdraw->afi = afi;
1631 mp_withdraw->safi = safi;
1632 mp_withdraw->nlri = stream_pnt (s);
1633 mp_withdraw->length = withdraw_len;
1634
paul9985f832005-02-09 15:51:56 +00001635 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001636
Paul Jakmab881c702010-11-23 16:35:42 +00001637 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001638}
1639
1640/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001641static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001642bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001643 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001644{
Paul Jakmab881c702010-11-23 16:35:42 +00001645 bgp_size_t total
1646 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1647
paul718e3742002-12-13 20:15:29 +00001648 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001649 {
1650 if (attr->extra)
1651 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001652 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001653 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001654 }
Paul Jakma0c466382010-12-05 17:17:26 +00001655
1656 (bgp_attr_extra_get (attr))->ecommunity =
1657 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1658 /* XXX: fix ecommunity_parse to use stream API */
1659 stream_forward_getp (peer->ibuf, length);
1660
1661 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001662 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1663 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1664 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001665
paul718e3742002-12-13 20:15:29 +00001666 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1667
Paul Jakmab881c702010-11-23 16:35:42 +00001668 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001669}
1670
1671/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001672static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001673bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1674 u_char type, bgp_size_t length, u_char *startp)
1675{
1676 bgp_size_t total;
1677 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001678 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001679
hassof4184462005-02-01 20:13:16 +00001680 if (BGP_DEBUG (normal, NORMAL))
1681 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1682 peer->host, type, length);
1683
paul718e3742002-12-13 20:15:29 +00001684 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001685 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001686 "Unknown attribute type %d length %d is received", type, length);
1687
1688 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001689 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001690
1691 /* Adjest total length to include type and length. */
1692 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1693
1694 /* If any of the mandatory well-known attributes are not recognized,
1695 then the Error Subcode is set to Unrecognized Well-known
1696 Attribute. The Data field contains the unrecognized attribute
1697 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001698 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001699 {
Paul Jakmab881c702010-11-23 16:35:42 +00001700 return bgp_attr_malformed (peer, type, flag,
1701 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1702 startp, total);
paul718e3742002-12-13 20:15:29 +00001703 }
1704
1705 /* Unrecognized non-transitive optional attributes must be quietly
1706 ignored and not passed along to other BGP peers. */
1707 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001708 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001709
1710 /* If a path with recognized transitive optional attribute is
1711 accepted and passed along to other BGP peers and the Partial bit
1712 in the Attribute Flags octet is set to 1 by some previous AS, it
1713 is not set back to 0 by the current AS. */
1714 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1715
1716 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001717 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001718 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001719
Paul Jakmafb982c22007-05-04 20:15:47 +00001720 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001721
1722 if (transit->val)
1723 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1724 transit->length + total);
1725 else
1726 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1727
1728 memcpy (transit->val + transit->length, startp, total);
1729 transit->length += total;
1730
Paul Jakmab881c702010-11-23 16:35:42 +00001731 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001732}
1733
1734/* Read attribute of update packet. This function is called from
1735 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001736bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001737bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1738 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1739{
1740 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001741 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001742 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001743 bgp_size_t length;
1744 u_char *startp, *endp;
1745 u_char *attr_endp;
1746 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001747 /* we need the as4_path only until we have synthesized the as_path with it */
1748 /* same goes for as4_aggregator */
1749 struct aspath *as4_path = NULL;
1750 as_t as4_aggregator = 0;
1751 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001752
1753 /* Initialize bitmap. */
1754 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1755
1756 /* End pointer of BGP attribute. */
1757 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001758
paul718e3742002-12-13 20:15:29 +00001759 /* Get attributes to the end of attribute length. */
1760 while (BGP_INPUT_PNT (peer) < endp)
1761 {
1762 /* Check remaining length check.*/
1763 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1764 {
gdtc29fdba2004-12-09 14:46:46 +00001765 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001766 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001767 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001768 peer->host,
1769 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001770
1771 bgp_notify_send (peer,
1772 BGP_NOTIFY_UPDATE_ERR,
1773 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001774 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001775 }
1776
1777 /* Fetch attribute flag and type. */
1778 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001779 /* "The lower-order four bits of the Attribute Flags octet are
1780 unused. They MUST be zero when sent and MUST be ignored when
1781 received." */
1782 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001783 type = stream_getc (BGP_INPUT (peer));
1784
Paul Jakma370b64a2007-12-22 16:49:52 +00001785 /* Check whether Extended-Length applies and is in bounds */
1786 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1787 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1788 {
1789 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001790 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001791 peer->host,
1792 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1793
1794 bgp_notify_send (peer,
1795 BGP_NOTIFY_UPDATE_ERR,
1796 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001797 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001798 }
1799
paul718e3742002-12-13 20:15:29 +00001800 /* Check extended attribue length bit. */
1801 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1802 length = stream_getw (BGP_INPUT (peer));
1803 else
1804 length = stream_getc (BGP_INPUT (peer));
1805
1806 /* If any attribute appears more than once in the UPDATE
1807 message, then the Error Subcode is set to Malformed Attribute
1808 List. */
1809
1810 if (CHECK_BITMAP (seen, type))
1811 {
1812 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001813 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001814 peer->host, type);
1815
1816 bgp_notify_send (peer,
1817 BGP_NOTIFY_UPDATE_ERR,
1818 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001819 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001820 }
1821
1822 /* Set type to bitmap to check duplicate attribute. `type' is
1823 unsigned char so it never overflow bitmap range. */
1824
1825 SET_BITMAP (seen, type);
1826
1827 /* Overflow check. */
1828 attr_endp = BGP_INPUT_PNT (peer) + length;
1829
1830 if (attr_endp > endp)
1831 {
1832 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001833 "%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 +00001834 bgp_notify_send (peer,
1835 BGP_NOTIFY_UPDATE_ERR,
1836 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001837 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001838 }
1839
1840 /* OK check attribute and store it's value. */
1841 switch (type)
1842 {
1843 case BGP_ATTR_ORIGIN:
1844 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1845 break;
1846 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001847 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001848 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001849 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001850 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001851 break;
paul718e3742002-12-13 20:15:29 +00001852 case BGP_ATTR_NEXT_HOP:
1853 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1854 break;
1855 case BGP_ATTR_MULTI_EXIT_DISC:
1856 ret = bgp_attr_med (peer, length, attr, flag, startp);
1857 break;
1858 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001859 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001860 break;
1861 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001862 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001863 break;
1864 case BGP_ATTR_AGGREGATOR:
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001865 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001866 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001867 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001868 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1869 &as4_aggregator,
1870 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001871 break;
paul718e3742002-12-13 20:15:29 +00001872 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001873 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001874 break;
1875 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienkod595b562011-09-30 15:08:54 +04001876 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001877 break;
1878 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienko0b830442011-09-30 15:12:17 +04001879 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001880 break;
1881 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001882 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001883 break;
1884 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001885 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001886 break;
1887 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001888 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001889 break;
1890 default:
1891 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1892 break;
1893 }
Paul Jakmab881c702010-11-23 16:35:42 +00001894
1895 /* If hard error occured immediately return to the caller. */
1896 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001897 {
1898 zlog (peer->log, LOG_WARNING,
1899 "%s: Attribute %s, parse error",
1900 peer->host,
1901 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001902 bgp_notify_send (peer,
1903 BGP_NOTIFY_UPDATE_ERR,
1904 BGP_NOTIFY_UPDATE_MAL_ATTR);
1905 if (as4_path)
1906 aspath_unintern (&as4_path);
1907 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001908 }
Paul Jakmab881c702010-11-23 16:35:42 +00001909 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1910 {
1911
1912 zlog (peer->log, LOG_WARNING,
1913 "%s: Attribute %s, parse error - treating as withdrawal",
1914 peer->host,
1915 LOOKUP (attr_str, type));
1916 if (as4_path)
1917 aspath_unintern (&as4_path);
1918 return ret;
1919 }
1920
paul718e3742002-12-13 20:15:29 +00001921 /* Check the fetched length. */
1922 if (BGP_INPUT_PNT (peer) != attr_endp)
1923 {
1924 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001925 "%s: BGP attribute %s, fetch error",
1926 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001927 bgp_notify_send (peer,
1928 BGP_NOTIFY_UPDATE_ERR,
1929 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001930 if (as4_path)
1931 aspath_unintern (&as4_path);
1932 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001933 }
1934 }
1935
1936 /* Check final read pointer is same as end pointer. */
1937 if (BGP_INPUT_PNT (peer) != endp)
1938 {
1939 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001940 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001941 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001942 bgp_notify_send (peer,
1943 BGP_NOTIFY_UPDATE_ERR,
1944 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001945 if (as4_path)
1946 aspath_unintern (&as4_path);
1947 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001948 }
1949
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001950 /*
1951 * At this place we can see whether we got AS4_PATH and/or
1952 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1953 * We can not do this before we've read all attributes because
1954 * the as4 handling does not say whether AS4_PATH has to be sent
1955 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1956 * in relationship to AGGREGATOR.
1957 * So, to be defensive, we are not relying on any order and read
1958 * all attributes first, including these 32bit ones, and now,
1959 * afterwards, we look what and if something is to be done for as4.
1960 */
Paul Jakmab881c702010-11-23 16:35:42 +00001961 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001962 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001963 {
1964 if (as4_path)
1965 aspath_unintern (&as4_path);
1966 return BGP_ATTR_PARSE_ERROR;
1967 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001968
1969 /* At this stage, we have done all fiddling with as4, and the
1970 * resulting info is in attr->aggregator resp. attr->aspath
1971 * so we can chuck as4_aggregator and as4_path alltogether in
1972 * order to save memory
1973 */
Paul Jakmab881c702010-11-23 16:35:42 +00001974 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001975 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001976 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001977 /* The flag that we got this is still there, but that does not
1978 * do any trouble
1979 */
1980 }
1981 /*
1982 * The "rest" of the code does nothing with as4_aggregator.
1983 * there is no memory attached specifically which is not part
1984 * of the attr.
1985 * so ignoring just means do nothing.
1986 */
1987 /*
1988 * Finally do the checks on the aspath we did not do yet
1989 * because we waited for a potentially synthesized aspath.
1990 */
Paul Jakmab881c702010-11-23 16:35:42 +00001991 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001992 {
Paul Jakmab881c702010-11-23 16:35:42 +00001993 ret = bgp_attr_aspath_check (peer, attr, flag);
1994 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001995 return ret;
1996 }
1997
paul718e3742002-12-13 20:15:29 +00001998 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001999 if (attr->extra && attr->extra->transit)
2000 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002001
Paul Jakmab881c702010-11-23 16:35:42 +00002002 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002003}
2004
2005/* Well-known attribute check. */
2006int
2007bgp_attr_check (struct peer *peer, struct attr *attr)
2008{
2009 u_char type = 0;
2010
2011 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2012 type = BGP_ATTR_ORIGIN;
2013
2014 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2015 type = BGP_ATTR_AS_PATH;
2016
2017 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2018 type = BGP_ATTR_NEXT_HOP;
2019
2020 if (peer_sort (peer) == BGP_PEER_IBGP
2021 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2022 type = BGP_ATTR_LOCAL_PREF;
2023
2024 if (type)
2025 {
2026 zlog (peer->log, LOG_WARNING,
2027 "%s Missing well-known attribute %d.",
2028 peer->host, type);
2029 bgp_notify_send_with_data (peer,
2030 BGP_NOTIFY_UPDATE_ERR,
2031 BGP_NOTIFY_UPDATE_MISS_ATTR,
2032 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002033 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002034 }
Paul Jakmab881c702010-11-23 16:35:42 +00002035 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002036}
2037
2038int stream_put_prefix (struct stream *, struct prefix *);
2039
2040/* Make attribute packet. */
2041bgp_size_t
2042bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2043 struct stream *s, struct attr *attr, struct prefix *p,
2044 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002045 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002046{
paulfe69a502005-09-10 16:55:02 +00002047 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002048 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002049 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002050 int send_as4_path = 0;
2051 int send_as4_aggregator = 0;
2052 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002053
2054 if (! bgp)
2055 bgp = bgp_get_default ();
2056
2057 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002058 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002059
2060 /* Origin attribute. */
2061 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2062 stream_putc (s, BGP_ATTR_ORIGIN);
2063 stream_putc (s, 1);
2064 stream_putc (s, attr->origin);
2065
2066 /* AS path attribute. */
2067
2068 /* If remote-peer is EBGP */
2069 if (peer_sort (peer) == BGP_PEER_EBGP
2070 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002071 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002072 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002073 {
2074 aspath = aspath_dup (attr->aspath);
2075
2076 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2077 {
2078 /* Strip the confed info, and then stuff our path CONFED_ID
2079 on the front */
2080 aspath = aspath_delete_confed_seq (aspath);
2081 aspath = aspath_add_seq (aspath, bgp->confed_id);
2082 }
2083 else
2084 {
2085 aspath = aspath_add_seq (aspath, peer->local_as);
2086 if (peer->change_local_as)
2087 aspath = aspath_add_seq (aspath, peer->change_local_as);
2088 }
2089 }
2090 else if (peer_sort (peer) == BGP_PEER_CONFED)
2091 {
2092 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2093 aspath = aspath_dup (attr->aspath);
2094 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2095 }
2096 else
2097 aspath = attr->aspath;
2098
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002099 /* If peer is not AS4 capable, then:
2100 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2101 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2102 * types are in it (i.e. exclude them if they are there)
2103 * AND do this only if there is at least one asnum > 65535 in the path!
2104 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2105 * all ASnums > 65535 to BGP_AS_TRANS
2106 */
paul718e3742002-12-13 20:15:29 +00002107
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002108 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2109 stream_putc (s, BGP_ATTR_AS_PATH);
2110 aspath_sizep = stream_get_endp (s);
2111 stream_putw (s, 0);
2112 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2113
2114 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2115 * in the path
2116 */
2117 if (!use32bit && aspath_has_as4 (aspath))
2118 send_as4_path = 1; /* we'll do this later, at the correct place */
2119
paul718e3742002-12-13 20:15:29 +00002120 /* Nexthop attribute. */
2121 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2122 {
2123 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2124 stream_putc (s, BGP_ATTR_NEXT_HOP);
2125 stream_putc (s, 4);
2126 if (safi == SAFI_MPLS_VPN)
2127 {
2128 if (attr->nexthop.s_addr == 0)
2129 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2130 else
2131 stream_put_ipv4 (s, attr->nexthop.s_addr);
2132 }
2133 else
2134 stream_put_ipv4 (s, attr->nexthop.s_addr);
2135 }
2136
2137 /* MED attribute. */
2138 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2139 {
2140 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2141 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2142 stream_putc (s, 4);
2143 stream_putl (s, attr->med);
2144 }
2145
2146 /* Local preference. */
2147 if (peer_sort (peer) == BGP_PEER_IBGP ||
2148 peer_sort (peer) == BGP_PEER_CONFED)
2149 {
2150 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2151 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2152 stream_putc (s, 4);
2153 stream_putl (s, attr->local_pref);
2154 }
2155
2156 /* Atomic aggregate. */
2157 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2158 {
2159 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2160 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2161 stream_putc (s, 0);
2162 }
2163
2164 /* Aggregator. */
2165 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2166 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002167 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002168
2169 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002170 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2171 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002172
2173 if (use32bit)
2174 {
2175 /* AS4 capable peer */
2176 stream_putc (s, 8);
2177 stream_putl (s, attr->extra->aggregator_as);
2178 }
2179 else
2180 {
2181 /* 2-byte AS peer */
2182 stream_putc (s, 6);
2183
2184 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2185 if ( attr->extra->aggregator_as > 65535 )
2186 {
2187 stream_putw (s, BGP_AS_TRANS);
2188
2189 /* we have to send AS4_AGGREGATOR, too.
2190 * we'll do that later in order to send attributes in ascending
2191 * order.
2192 */
2193 send_as4_aggregator = 1;
2194 }
2195 else
2196 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2197 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002198 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002199 }
2200
2201 /* Community attribute. */
2202 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2203 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2204 {
2205 if (attr->community->size * 4 > 255)
2206 {
2207 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2208 stream_putc (s, BGP_ATTR_COMMUNITIES);
2209 stream_putw (s, attr->community->size * 4);
2210 }
2211 else
2212 {
2213 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2214 stream_putc (s, BGP_ATTR_COMMUNITIES);
2215 stream_putc (s, attr->community->size * 4);
2216 }
2217 stream_put (s, attr->community->val, attr->community->size * 4);
2218 }
2219
2220 /* Route Reflector. */
2221 if (peer_sort (peer) == BGP_PEER_IBGP
2222 && from
2223 && peer_sort (from) == BGP_PEER_IBGP)
2224 {
2225 /* Originator ID. */
2226 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2227 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2228 stream_putc (s, 4);
2229
2230 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002231 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002232 else
2233 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002234
2235 /* Cluster list. */
2236 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2237 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2238
Paul Jakma9eda90c2007-08-30 13:36:17 +00002239 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002240 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002241 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002242 /* If this peer configuration's parent BGP has cluster_id. */
2243 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2244 stream_put_in_addr (s, &bgp->cluster_id);
2245 else
2246 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002247 stream_put (s, attr->extra->cluster->list,
2248 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002249 }
2250 else
2251 {
2252 stream_putc (s, 4);
2253 /* If this peer configuration's parent BGP has cluster_id. */
2254 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2255 stream_put_in_addr (s, &bgp->cluster_id);
2256 else
2257 stream_put_in_addr (s, &bgp->router_id);
2258 }
2259 }
2260
2261#ifdef HAVE_IPV6
2262 /* If p is IPv6 address put it into attribute. */
2263 if (p->family == AF_INET6)
2264 {
2265 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002266 struct attr_extra *attre = attr->extra;
2267
2268 assert (attr->extra);
2269
paul718e3742002-12-13 20:15:29 +00002270 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2271 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002272 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002273 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002274 stream_putw (s, AFI_IP6); /* AFI */
2275 stream_putc (s, safi); /* SAFI */
2276
Paul Jakmafb982c22007-05-04 20:15:47 +00002277 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002278
Paul Jakmafb982c22007-05-04 20:15:47 +00002279 if (attre->mp_nexthop_len == 16)
2280 stream_put (s, &attre->mp_nexthop_global, 16);
2281 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002282 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002283 stream_put (s, &attre->mp_nexthop_global, 16);
2284 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002285 }
2286
2287 /* SNPA */
2288 stream_putc (s, 0);
2289
paul718e3742002-12-13 20:15:29 +00002290 /* Prefix write. */
2291 stream_put_prefix (s, p);
2292
2293 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002294 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002295 }
2296#endif /* HAVE_IPV6 */
2297
2298 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2299 {
2300 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002301
2302 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2303 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002304 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002305 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002306 stream_putw (s, AFI_IP); /* AFI */
2307 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2308
2309 stream_putc (s, 4);
2310 stream_put_ipv4 (s, attr->nexthop.s_addr);
2311
2312 /* SNPA */
2313 stream_putc (s, 0);
2314
paul718e3742002-12-13 20:15:29 +00002315 /* Prefix write. */
2316 stream_put_prefix (s, p);
2317
2318 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002319 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002320 }
2321
2322 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2323 {
2324 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002325
2326 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2327 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002328 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002329 stream_putc (s, 0); /* Length of this attribute. */
2330 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002331 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002332
2333 stream_putc (s, 12);
2334 stream_putl (s, 0);
2335 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002336 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002337
2338 /* SNPA */
2339 stream_putc (s, 0);
2340
paul718e3742002-12-13 20:15:29 +00002341 /* Tag, RD, Prefix write. */
2342 stream_putc (s, p->prefixlen + 88);
2343 stream_put (s, tag, 3);
2344 stream_put (s, prd->val, 8);
2345 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2346
2347 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002348 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002349 }
2350
2351 /* Extended Communities attribute. */
2352 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2353 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2354 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002355 struct attr_extra *attre = attr->extra;
2356
2357 assert (attre);
2358
2359 if (peer_sort (peer) == BGP_PEER_IBGP
2360 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002361 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002362 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002363 {
2364 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2365 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002366 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002367 }
2368 else
2369 {
2370 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2371 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002372 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002373 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002374 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002375 }
2376 else
2377 {
paul5228ad22004-06-04 17:58:18 +00002378 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002379 int tbit;
2380 int ecom_tr_size = 0;
2381 int i;
2382
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002384 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002385 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002386 tbit = *pnt;
2387
2388 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2389 continue;
2390
2391 ecom_tr_size++;
2392 }
2393
2394 if (ecom_tr_size)
2395 {
2396 if (ecom_tr_size * 8 > 255)
2397 {
2398 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2399 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2400 stream_putw (s, ecom_tr_size * 8);
2401 }
2402 else
2403 {
2404 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2405 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2406 stream_putc (s, ecom_tr_size * 8);
2407 }
2408
Paul Jakmafb982c22007-05-04 20:15:47 +00002409 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002410 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002412 tbit = *pnt;
2413
2414 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2415 continue;
2416
2417 stream_put (s, pnt, 8);
2418 }
2419 }
paul718e3742002-12-13 20:15:29 +00002420 }
paul718e3742002-12-13 20:15:29 +00002421 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002422
2423 if ( send_as4_path )
2424 {
2425 /* If the peer is NOT As4 capable, AND */
2426 /* there are ASnums > 65535 in path THEN
2427 * give out AS4_PATH */
2428
2429 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2430 * path segments!
2431 * Hm, I wonder... confederation things *should* only be at
2432 * the beginning of an aspath, right? Then we should use
2433 * aspath_delete_confed_seq for this, because it is already
2434 * there! (JK)
2435 * Folks, talk to me: what is reasonable here!?
2436 */
2437 aspath = aspath_delete_confed_seq (aspath);
2438
2439 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2440 stream_putc (s, BGP_ATTR_AS4_PATH);
2441 aspath_sizep = stream_get_endp (s);
2442 stream_putw (s, 0);
2443 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2444 }
2445
2446 if (aspath != attr->aspath)
2447 aspath_free (aspath);
2448
2449 if ( send_as4_aggregator )
2450 {
2451 assert (attr->extra);
2452
2453 /* send AS4_AGGREGATOR, at this place */
2454 /* this section of code moved here in order to ensure the correct
2455 * *ascending* order of attributes
2456 */
2457 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2458 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2459 stream_putc (s, 8);
2460 stream_putl (s, attr->extra->aggregator_as);
2461 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2462 }
Paul Jakma41367172007-08-06 15:24:51 +00002463
paul718e3742002-12-13 20:15:29 +00002464 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002465 if (attr->extra && attr->extra->transit)
2466 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002467
2468 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002469 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002470}
2471
2472bgp_size_t
2473bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2474 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002475 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002476{
2477 unsigned long cp;
2478 unsigned long attrlen_pnt;
2479 bgp_size_t size;
2480
paul9985f832005-02-09 15:51:56 +00002481 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002482
2483 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2484 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2485
paul9985f832005-02-09 15:51:56 +00002486 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002487 stream_putc (s, 0); /* Length of this attribute. */
2488
2489 stream_putw (s, family2afi (p->family));
2490
2491 if (safi == SAFI_MPLS_VPN)
2492 {
2493 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002494 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002495
2496 /* prefix. */
2497 stream_putc (s, p->prefixlen + 88);
2498 stream_put (s, tag, 3);
2499 stream_put (s, prd->val, 8);
2500 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2501 }
2502 else
2503 {
2504 /* SAFI */
2505 stream_putc (s, safi);
2506
2507 /* prefix */
2508 stream_put_prefix (s, p);
2509 }
2510
2511 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002512 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002513 stream_putc_at (s, attrlen_pnt, size);
2514
paul9985f832005-02-09 15:51:56 +00002515 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002516}
2517
2518/* Initialization of attribute. */
2519void
paulfe69a502005-09-10 16:55:02 +00002520bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002521{
paul718e3742002-12-13 20:15:29 +00002522 aspath_init ();
2523 attrhash_init ();
2524 community_init ();
2525 ecommunity_init ();
2526 cluster_init ();
2527 transit_init ();
2528}
2529
Chris Caputo228da422009-07-18 05:44:03 +00002530void
2531bgp_attr_finish (void)
2532{
2533 aspath_finish ();
2534 attrhash_finish ();
2535 community_finish ();
2536 ecommunity_finish ();
2537 cluster_finish ();
2538 transit_finish ();
2539}
2540
paul718e3742002-12-13 20:15:29 +00002541/* Make attribute packet. */
2542void
paula3845922003-10-18 01:30:50 +00002543bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2544 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002545{
2546 unsigned long cp;
2547 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002548 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002549 struct aspath *aspath;
2550
2551 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002552 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002553
2554 /* Place holder of length. */
2555 stream_putw (s, 0);
2556
2557 /* Origin attribute. */
2558 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2559 stream_putc (s, BGP_ATTR_ORIGIN);
2560 stream_putc (s, 1);
2561 stream_putc (s, attr->origin);
2562
2563 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002564
2565 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2566 stream_putc (s, BGP_ATTR_AS_PATH);
2567 aspath_lenp = stream_get_endp (s);
2568 stream_putw (s, 0);
2569
2570 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002571
2572 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002573 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2574 if(prefix != NULL
2575#ifdef HAVE_IPV6
2576 && prefix->family != AF_INET6
2577#endif /* HAVE_IPV6 */
2578 )
2579 {
2580 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2581 stream_putc (s, BGP_ATTR_NEXT_HOP);
2582 stream_putc (s, 4);
2583 stream_put_ipv4 (s, attr->nexthop.s_addr);
2584 }
paul718e3742002-12-13 20:15:29 +00002585
2586 /* MED attribute. */
2587 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2588 {
2589 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2590 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2591 stream_putc (s, 4);
2592 stream_putl (s, attr->med);
2593 }
2594
2595 /* Local preference. */
2596 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2597 {
2598 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2599 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2600 stream_putc (s, 4);
2601 stream_putl (s, attr->local_pref);
2602 }
2603
2604 /* Atomic aggregate. */
2605 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2606 {
2607 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2608 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2609 stream_putc (s, 0);
2610 }
2611
2612 /* Aggregator. */
2613 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2614 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002615 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002616 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2617 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002618 stream_putc (s, 8);
2619 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002620 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002621 }
2622
2623 /* Community attribute. */
2624 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2625 {
2626 if (attr->community->size * 4 > 255)
2627 {
2628 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2629 stream_putc (s, BGP_ATTR_COMMUNITIES);
2630 stream_putw (s, attr->community->size * 4);
2631 }
2632 else
2633 {
2634 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2635 stream_putc (s, BGP_ATTR_COMMUNITIES);
2636 stream_putc (s, attr->community->size * 4);
2637 }
2638 stream_put (s, attr->community->val, attr->community->size * 4);
2639 }
2640
paula3845922003-10-18 01:30:50 +00002641#ifdef HAVE_IPV6
2642 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002643 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2644 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002645 {
2646 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002647 struct attr_extra *attre = attr->extra;
2648
paula3845922003-10-18 01:30:50 +00002649 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2650 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002651 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002652
2653 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002654 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002655 stream_putw(s, AFI_IP6); /* AFI */
2656 stream_putc(s, SAFI_UNICAST); /* SAFI */
2657
2658 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002659 stream_putc(s, attre->mp_nexthop_len);
2660 stream_put(s, &attre->mp_nexthop_global, 16);
2661 if (attre->mp_nexthop_len == 32)
2662 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002663
2664 /* SNPA */
2665 stream_putc(s, 0);
2666
2667 /* Prefix */
2668 stream_put_prefix(s, prefix);
2669
2670 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002671 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002672 }
2673#endif /* HAVE_IPV6 */
2674
paul718e3742002-12-13 20:15:29 +00002675 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002676 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002677 stream_putw_at (s, cp, len);
2678}