blob: c2e5fede15b422a18f6d91159b867b45e6c0ad5c [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);
1046 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1047 return -1;
1048 }
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001049
paul718e3742002-12-13 20:15:29 +00001050 /* Length check. */
1051 if (length != 4)
1052 {
1053 zlog (peer->log, LOG_ERR,
1054 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001055
1056 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1057 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1058 startp, total);
paul718e3742002-12-13 20:15:29 +00001059 }
1060
1061 attr->med = stream_getl (peer->ibuf);
1062
1063 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1064
Paul Jakmab881c702010-11-23 16:35:42 +00001065 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001066}
1067
1068/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001069static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001070bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001071 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001072{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001073 bgp_size_t total;
1074
1075 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1076 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001077 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001078 {
1079 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1080 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1081 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1082 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1083 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1084 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1085 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1086 return -1;
1087 }
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001088 /* Length check. */
1089 if (length != 4)
1090 {
1091 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
1092 bgp_notify_send_with_data (peer,
1093 BGP_NOTIFY_UPDATE_ERR,
1094 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1095 startp, total);
1096 return -1;
1097 }
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);
1133 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1134 return -1;
1135 }
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001136
1137 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001138 if (length != 0)
1139 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001140 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001141 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1142 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001143 startp, total);
paul718e3742002-12-13 20:15:29 +00001144 }
1145
1146 /* Set atomic aggregate flag. */
1147 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1148
Paul Jakmab881c702010-11-23 16:35:42 +00001149 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001150}
1151
1152/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001153static int
paul718e3742002-12-13 20:15:29 +00001154bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001155 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001156{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001157 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001158 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001159 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001160
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001161 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001162 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001163 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001164 wantedlen = 8;
1165
1166 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001167 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001168 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001169 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1170 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001171 startp, total);
paul718e3742002-12-13 20:15:29 +00001172 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001173
1174 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1175 attre->aggregator_as = stream_getl (peer->ibuf);
1176 else
1177 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001178 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001179
1180 /* Set atomic aggregate flag. */
1181 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1182
Paul Jakmab881c702010-11-23 16:35:42 +00001183 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001184}
1185
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001186/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001187static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001188bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001189 struct attr *attr, u_char flag,
1190 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001191 struct in_addr *as4_aggregator_addr)
1192{
1193 if (length != 8)
1194 {
1195 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001196 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1197 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1198 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001199 }
1200 *as4_aggregator_as = stream_getl (peer->ibuf);
1201 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1202
1203 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1204
Paul Jakmab881c702010-11-23 16:35:42 +00001205 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001206}
1207
1208/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1209 */
Paul Jakmab881c702010-11-23 16:35:42 +00001210static bgp_attr_parse_ret_t
1211bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001212 struct aspath *as4_path, as_t as4_aggregator,
1213 struct in_addr *as4_aggregator_addr)
1214{
1215 int ignore_as4_path = 0;
1216 struct aspath *newpath;
1217 struct attr_extra *attre = attr->extra;
1218
Paul Jakmab881c702010-11-23 16:35:42 +00001219 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001220 {
1221 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1222 * if given.
1223 * It is worth a warning though, because the peer really
1224 * should not send them
1225 */
1226 if (BGP_DEBUG(as4, AS4))
1227 {
1228 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1229 zlog_debug ("[AS4] %s %s AS4_PATH",
1230 peer->host, "AS4 capable peer, yet it sent");
1231
1232 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1233 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1234 peer->host, "AS4 capable peer, yet it sent");
1235 }
1236
Paul Jakmab881c702010-11-23 16:35:42 +00001237 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001238 }
1239
Paul Jakmab881c702010-11-23 16:35:42 +00001240 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1241 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001242 {
1243 /* Hu? This is not supposed to happen at all!
1244 * got as4_path and no aspath,
1245 * This should already
1246 * have been handled by 'well known attributes missing'
1247 * But... yeah, paranoia
1248 * Take this as a "malformed attribute"
1249 */
1250 zlog (peer->log, LOG_ERR,
1251 "%s BGP not AS4 capable peer sent AS4_PATH but"
1252 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001253 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1254 BGP_NOTIFY_UPDATE_MAL_ATTR,
1255 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001256 }
1257
1258 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1259 * because that may override AS4_PATH
1260 */
1261 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1262 {
Paul Jakmab881c702010-11-23 16:35:42 +00001263 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001264 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001265 assert (attre);
1266
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001267 /* received both.
1268 * if the as_number in aggregator is not AS_TRANS,
1269 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1270 * and the Aggregator shall be taken as
1271 * info on the aggregating node, and the AS_PATH
1272 * shall be taken as the AS_PATH
1273 * otherwise
1274 * the Aggregator shall be ignored and the
1275 * AS4_AGGREGATOR shall be taken as the
1276 * Aggregating node and the AS_PATH is to be
1277 * constructed "as in all other cases"
1278 */
Paul Jakmab881c702010-11-23 16:35:42 +00001279 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001280 {
1281 /* ignore */
1282 if ( BGP_DEBUG(as4, AS4))
1283 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1284 " send AGGREGATOR != AS_TRANS and"
1285 " AS4_AGGREGATOR, so ignore"
1286 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1287 ignore_as4_path = 1;
1288 }
1289 else
1290 {
1291 /* "New_aggregator shall be taken as aggregator" */
1292 attre->aggregator_as = as4_aggregator;
1293 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1294 }
1295 }
1296 else
1297 {
1298 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1299 * That is bogus - but reading the conditions
1300 * we have to handle AS4_AGGREGATOR as if it were
1301 * AGGREGATOR in that case
1302 */
1303 if ( BGP_DEBUG(as4, AS4))
1304 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1305 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1306 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001307 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001308 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1309 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1310 }
1311 }
1312
1313 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001314 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001315 {
1316 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001317 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001318 attr->aspath = aspath_intern (newpath);
1319 }
Paul Jakmab881c702010-11-23 16:35:42 +00001320 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001321}
1322
paul718e3742002-12-13 20:15:29 +00001323/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001324static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001325bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001326 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001327{
Paul Jakmab881c702010-11-23 16:35:42 +00001328 bgp_size_t total
1329 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1330
paul718e3742002-12-13 20:15:29 +00001331 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001332 {
1333 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001334 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001335 }
Paul Jakma0c466382010-12-05 17:17:26 +00001336
1337 attr->community =
1338 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1339
1340 /* XXX: fix community_parse to use stream API and remove this */
1341 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001342
Paul Jakma0c466382010-12-05 17:17:26 +00001343 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001344 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1345 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1346 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001347
paul718e3742002-12-13 20:15:29 +00001348 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1349
Paul Jakmab881c702010-11-23 16:35:42 +00001350 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001351}
1352
1353/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001354static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001355bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienkod595b562011-09-30 15:08:54 +04001356 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001357{
Denis Ovsienkod595b562011-09-30 15:08:54 +04001358 bgp_size_t total;
1359
1360 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1361 /* Flag checks. */
1362 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1363 {
1364 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1365 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1366 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1367 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1368 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1369 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
1370 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1371 return -1;
1372 }
1373 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001374 if (length != 4)
1375 {
1376 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1377
Paul Jakmab881c702010-11-23 16:35:42 +00001378 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1379 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1380 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001381 }
1382
Paul Jakmafb982c22007-05-04 20:15:47 +00001383 (bgp_attr_extra_get (attr))->originator_id.s_addr
1384 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001385
1386 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1387
Paul Jakmab881c702010-11-23 16:35:42 +00001388 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001389}
1390
1391/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001392static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001393bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienko0b830442011-09-30 15:12:17 +04001394 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001395{
Denis Ovsienko0b830442011-09-30 15:12:17 +04001396 bgp_size_t total;
1397
1398 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1399 /* Flag checks. */
1400 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1401 {
1402 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1403 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1404 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1405 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1406 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1407 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
1408 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1409 return -1;
1410 }
paul718e3742002-12-13 20:15:29 +00001411 /* Check length. */
1412 if (length % 4)
1413 {
1414 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1415
Paul Jakmab881c702010-11-23 16:35:42 +00001416 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1417 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1418 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001419 }
1420
Paul Jakmafb982c22007-05-04 20:15:47 +00001421 (bgp_attr_extra_get (attr))->cluster
1422 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001423
1424 /* XXX: Fix cluster_parse to use stream API and then remove this */
1425 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001426
1427 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1428
Paul Jakmab881c702010-11-23 16:35:42 +00001429 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001430}
1431
1432/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001433int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001434bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1435 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001436{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001437 afi_t afi;
1438 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001439 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001440 size_t start;
paul718e3742002-12-13 20:15:29 +00001441 int ret;
1442 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001443 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001444 bgp_size_t total;
1445
1446 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1447 /* Flag checks. */
1448 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1449 {
1450 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1451 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1452 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1453 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1454 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1455 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
1456 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1457 return -1;
1458 }
paul718e3742002-12-13 20:15:29 +00001459 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001460 s = BGP_INPUT(peer);
1461 start = stream_get_getp(s);
1462
1463 /* safe to read statically sized header? */
1464#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001465#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001466 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001467 {
1468 zlog_info ("%s: %s sent invalid length, %lu",
1469 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001470 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001471 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001472
paul718e3742002-12-13 20:15:29 +00001473 /* Load AFI, SAFI. */
1474 afi = stream_getw (s);
1475 safi = stream_getc (s);
1476
1477 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001478 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001479
Paul Jakma03292802008-06-07 20:37:10 +00001480 if (LEN_LEFT < attre->mp_nexthop_len)
1481 {
1482 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1483 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001484 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001485 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001486
paul718e3742002-12-13 20:15:29 +00001487 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001488 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001489 {
1490 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001491 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001492 /* Probably needed for RFC 2283 */
1493 if (attr->nexthop.s_addr == 0)
1494 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001495 break;
1496 case 12:
1497 {
1498 u_int32_t rd_high;
1499 u_int32_t rd_low;
1500
1501 rd_high = stream_getl (s);
1502 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001503 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001504 }
1505 break;
1506#ifdef HAVE_IPV6
1507 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001508 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001509 break;
1510 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001511 stream_get (&attre->mp_nexthop_global, s, 16);
1512 stream_get (&attre->mp_nexthop_local, s, 16);
1513 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001514 {
1515 char buf1[INET6_ADDRSTRLEN];
1516 char buf2[INET6_ADDRSTRLEN];
1517
1518 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001519 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 +00001520 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001521 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001522 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001523 buf2, INET6_ADDRSTRLEN));
1524
Paul Jakmafb982c22007-05-04 20:15:47 +00001525 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001526 }
1527 break;
1528#endif /* HAVE_IPV6 */
1529 default:
Paul Jakma03292802008-06-07 20:37:10 +00001530 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1531 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001532 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001533 }
1534
Paul Jakma03292802008-06-07 20:37:10 +00001535 if (!LEN_LEFT)
1536 {
1537 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1538 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001539 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001540 }
paul718e3742002-12-13 20:15:29 +00001541
Paul Jakma6e4ab122007-04-10 19:36:48 +00001542 {
1543 u_char val;
1544 if ((val = stream_getc (s)))
1545 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1546 peer->host, val);
1547 }
1548
1549 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001550 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001551 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001552 {
1553 zlog_info ("%s: (%s) Failed to read NLRI",
1554 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001555 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001556 }
paul718e3742002-12-13 20:15:29 +00001557
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001558 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001559 {
1560 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001561 if (ret < 0)
1562 {
1563 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1564 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001565 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001566 }
paul718e3742002-12-13 20:15:29 +00001567 }
1568
1569 mp_update->afi = afi;
1570 mp_update->safi = safi;
1571 mp_update->nlri = stream_pnt (s);
1572 mp_update->length = nlri_len;
1573
paul9985f832005-02-09 15:51:56 +00001574 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001575
Paul Jakmab881c702010-11-23 16:35:42 +00001576 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001577#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001578}
1579
1580/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001581int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001582bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1583 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001584 struct bgp_nlri *mp_withdraw)
1585{
1586 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001587 afi_t afi;
1588 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001589 u_int16_t withdraw_len;
1590 int ret;
Denis Ovsienko565b8282011-10-10 21:08:33 +04001591 bgp_size_t total;
1592
1593 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1594 /* Flag checks. */
1595 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1596 {
1597 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1598 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1599 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1600 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1601 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1602 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
1603 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1604 return -1;
1605 }
paul718e3742002-12-13 20:15:29 +00001606
1607 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001608
1609#define BGP_MP_UNREACH_MIN_SIZE 3
1610 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001611 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001612
paul718e3742002-12-13 20:15:29 +00001613 afi = stream_getw (s);
1614 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001615
1616 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001617
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001618 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001619 {
1620 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1621 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001622 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001623 }
1624
1625 mp_withdraw->afi = afi;
1626 mp_withdraw->safi = safi;
1627 mp_withdraw->nlri = stream_pnt (s);
1628 mp_withdraw->length = withdraw_len;
1629
paul9985f832005-02-09 15:51:56 +00001630 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001631
Paul Jakmab881c702010-11-23 16:35:42 +00001632 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001633}
1634
1635/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001636static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001637bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001638 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001639{
Paul Jakmab881c702010-11-23 16:35:42 +00001640 bgp_size_t total
1641 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1642
paul718e3742002-12-13 20:15:29 +00001643 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001644 {
1645 if (attr->extra)
1646 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001647 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001648 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001649 }
Paul Jakma0c466382010-12-05 17:17:26 +00001650
1651 (bgp_attr_extra_get (attr))->ecommunity =
1652 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1653 /* XXX: fix ecommunity_parse to use stream API */
1654 stream_forward_getp (peer->ibuf, length);
1655
1656 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001657 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1658 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1659 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001660
paul718e3742002-12-13 20:15:29 +00001661 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1662
Paul Jakmab881c702010-11-23 16:35:42 +00001663 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001664}
1665
1666/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001667static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001668bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1669 u_char type, bgp_size_t length, u_char *startp)
1670{
1671 bgp_size_t total;
1672 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001673 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001674
hassof4184462005-02-01 20:13:16 +00001675 if (BGP_DEBUG (normal, NORMAL))
1676 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1677 peer->host, type, length);
1678
paul718e3742002-12-13 20:15:29 +00001679 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001680 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001681 "Unknown attribute type %d length %d is received", type, length);
1682
1683 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001684 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001685
1686 /* Adjest total length to include type and length. */
1687 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1688
1689 /* If any of the mandatory well-known attributes are not recognized,
1690 then the Error Subcode is set to Unrecognized Well-known
1691 Attribute. The Data field contains the unrecognized attribute
1692 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001693 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001694 {
Paul Jakmab881c702010-11-23 16:35:42 +00001695 return bgp_attr_malformed (peer, type, flag,
1696 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1697 startp, total);
paul718e3742002-12-13 20:15:29 +00001698 }
1699
1700 /* Unrecognized non-transitive optional attributes must be quietly
1701 ignored and not passed along to other BGP peers. */
1702 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001703 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001704
1705 /* If a path with recognized transitive optional attribute is
1706 accepted and passed along to other BGP peers and the Partial bit
1707 in the Attribute Flags octet is set to 1 by some previous AS, it
1708 is not set back to 0 by the current AS. */
1709 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1710
1711 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001712 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001713 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001714
Paul Jakmafb982c22007-05-04 20:15:47 +00001715 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001716
1717 if (transit->val)
1718 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1719 transit->length + total);
1720 else
1721 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1722
1723 memcpy (transit->val + transit->length, startp, total);
1724 transit->length += total;
1725
Paul Jakmab881c702010-11-23 16:35:42 +00001726 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001727}
1728
1729/* Read attribute of update packet. This function is called from
1730 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001731bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001732bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1733 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1734{
1735 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001736 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001737 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001738 bgp_size_t length;
1739 u_char *startp, *endp;
1740 u_char *attr_endp;
1741 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001742 /* we need the as4_path only until we have synthesized the as_path with it */
1743 /* same goes for as4_aggregator */
1744 struct aspath *as4_path = NULL;
1745 as_t as4_aggregator = 0;
1746 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001747
1748 /* Initialize bitmap. */
1749 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1750
1751 /* End pointer of BGP attribute. */
1752 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001753
paul718e3742002-12-13 20:15:29 +00001754 /* Get attributes to the end of attribute length. */
1755 while (BGP_INPUT_PNT (peer) < endp)
1756 {
1757 /* Check remaining length check.*/
1758 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1759 {
gdtc29fdba2004-12-09 14:46:46 +00001760 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001761 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001762 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001763 peer->host,
1764 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001765
1766 bgp_notify_send (peer,
1767 BGP_NOTIFY_UPDATE_ERR,
1768 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001769 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001770 }
1771
1772 /* Fetch attribute flag and type. */
1773 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001774 /* "The lower-order four bits of the Attribute Flags octet are
1775 unused. They MUST be zero when sent and MUST be ignored when
1776 received." */
1777 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001778 type = stream_getc (BGP_INPUT (peer));
1779
Paul Jakma370b64a2007-12-22 16:49:52 +00001780 /* Check whether Extended-Length applies and is in bounds */
1781 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1782 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1783 {
1784 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001785 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001786 peer->host,
1787 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1788
1789 bgp_notify_send (peer,
1790 BGP_NOTIFY_UPDATE_ERR,
1791 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001792 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001793 }
1794
paul718e3742002-12-13 20:15:29 +00001795 /* Check extended attribue length bit. */
1796 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1797 length = stream_getw (BGP_INPUT (peer));
1798 else
1799 length = stream_getc (BGP_INPUT (peer));
1800
1801 /* If any attribute appears more than once in the UPDATE
1802 message, then the Error Subcode is set to Malformed Attribute
1803 List. */
1804
1805 if (CHECK_BITMAP (seen, type))
1806 {
1807 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001808 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001809 peer->host, type);
1810
1811 bgp_notify_send (peer,
1812 BGP_NOTIFY_UPDATE_ERR,
1813 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001814 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001815 }
1816
1817 /* Set type to bitmap to check duplicate attribute. `type' is
1818 unsigned char so it never overflow bitmap range. */
1819
1820 SET_BITMAP (seen, type);
1821
1822 /* Overflow check. */
1823 attr_endp = BGP_INPUT_PNT (peer) + length;
1824
1825 if (attr_endp > endp)
1826 {
1827 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001828 "%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 +00001829 bgp_notify_send (peer,
1830 BGP_NOTIFY_UPDATE_ERR,
1831 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001832 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001833 }
1834
1835 /* OK check attribute and store it's value. */
1836 switch (type)
1837 {
1838 case BGP_ATTR_ORIGIN:
1839 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1840 break;
1841 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001842 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001843 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001844 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001845 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001846 break;
paul718e3742002-12-13 20:15:29 +00001847 case BGP_ATTR_NEXT_HOP:
1848 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1849 break;
1850 case BGP_ATTR_MULTI_EXIT_DISC:
1851 ret = bgp_attr_med (peer, length, attr, flag, startp);
1852 break;
1853 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001854 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001855 break;
1856 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001857 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001858 break;
1859 case BGP_ATTR_AGGREGATOR:
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001860 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001861 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001862 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001863 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1864 &as4_aggregator,
1865 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001866 break;
paul718e3742002-12-13 20:15:29 +00001867 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001868 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001869 break;
1870 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienkod595b562011-09-30 15:08:54 +04001871 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001872 break;
1873 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienko0b830442011-09-30 15:12:17 +04001874 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001875 break;
1876 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001877 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001878 break;
1879 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001880 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001881 break;
1882 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001883 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001884 break;
1885 default:
1886 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1887 break;
1888 }
Paul Jakmab881c702010-11-23 16:35:42 +00001889
1890 /* If hard error occured immediately return to the caller. */
1891 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001892 {
1893 zlog (peer->log, LOG_WARNING,
1894 "%s: Attribute %s, parse error",
1895 peer->host,
1896 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001897 bgp_notify_send (peer,
1898 BGP_NOTIFY_UPDATE_ERR,
1899 BGP_NOTIFY_UPDATE_MAL_ATTR);
1900 if (as4_path)
1901 aspath_unintern (&as4_path);
1902 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001903 }
Paul Jakmab881c702010-11-23 16:35:42 +00001904 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1905 {
1906
1907 zlog (peer->log, LOG_WARNING,
1908 "%s: Attribute %s, parse error - treating as withdrawal",
1909 peer->host,
1910 LOOKUP (attr_str, type));
1911 if (as4_path)
1912 aspath_unintern (&as4_path);
1913 return ret;
1914 }
1915
paul718e3742002-12-13 20:15:29 +00001916 /* Check the fetched length. */
1917 if (BGP_INPUT_PNT (peer) != attr_endp)
1918 {
1919 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001920 "%s: BGP attribute %s, fetch error",
1921 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001922 bgp_notify_send (peer,
1923 BGP_NOTIFY_UPDATE_ERR,
1924 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001925 if (as4_path)
1926 aspath_unintern (&as4_path);
1927 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001928 }
1929 }
1930
1931 /* Check final read pointer is same as end pointer. */
1932 if (BGP_INPUT_PNT (peer) != endp)
1933 {
1934 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001935 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001936 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001937 bgp_notify_send (peer,
1938 BGP_NOTIFY_UPDATE_ERR,
1939 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001940 if (as4_path)
1941 aspath_unintern (&as4_path);
1942 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001943 }
1944
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001945 /*
1946 * At this place we can see whether we got AS4_PATH and/or
1947 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1948 * We can not do this before we've read all attributes because
1949 * the as4 handling does not say whether AS4_PATH has to be sent
1950 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1951 * in relationship to AGGREGATOR.
1952 * So, to be defensive, we are not relying on any order and read
1953 * all attributes first, including these 32bit ones, and now,
1954 * afterwards, we look what and if something is to be done for as4.
1955 */
Paul Jakmab881c702010-11-23 16:35:42 +00001956 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001957 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001958 {
1959 if (as4_path)
1960 aspath_unintern (&as4_path);
1961 return BGP_ATTR_PARSE_ERROR;
1962 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001963
1964 /* At this stage, we have done all fiddling with as4, and the
1965 * resulting info is in attr->aggregator resp. attr->aspath
1966 * so we can chuck as4_aggregator and as4_path alltogether in
1967 * order to save memory
1968 */
Paul Jakmab881c702010-11-23 16:35:42 +00001969 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001970 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001971 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001972 /* The flag that we got this is still there, but that does not
1973 * do any trouble
1974 */
1975 }
1976 /*
1977 * The "rest" of the code does nothing with as4_aggregator.
1978 * there is no memory attached specifically which is not part
1979 * of the attr.
1980 * so ignoring just means do nothing.
1981 */
1982 /*
1983 * Finally do the checks on the aspath we did not do yet
1984 * because we waited for a potentially synthesized aspath.
1985 */
Paul Jakmab881c702010-11-23 16:35:42 +00001986 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001987 {
Paul Jakmab881c702010-11-23 16:35:42 +00001988 ret = bgp_attr_aspath_check (peer, attr, flag);
1989 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001990 return ret;
1991 }
1992
paul718e3742002-12-13 20:15:29 +00001993 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001994 if (attr->extra && attr->extra->transit)
1995 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001996
Paul Jakmab881c702010-11-23 16:35:42 +00001997 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001998}
1999
2000/* Well-known attribute check. */
2001int
2002bgp_attr_check (struct peer *peer, struct attr *attr)
2003{
2004 u_char type = 0;
2005
2006 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2007 type = BGP_ATTR_ORIGIN;
2008
2009 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2010 type = BGP_ATTR_AS_PATH;
2011
2012 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2013 type = BGP_ATTR_NEXT_HOP;
2014
2015 if (peer_sort (peer) == BGP_PEER_IBGP
2016 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2017 type = BGP_ATTR_LOCAL_PREF;
2018
2019 if (type)
2020 {
2021 zlog (peer->log, LOG_WARNING,
2022 "%s Missing well-known attribute %d.",
2023 peer->host, type);
2024 bgp_notify_send_with_data (peer,
2025 BGP_NOTIFY_UPDATE_ERR,
2026 BGP_NOTIFY_UPDATE_MISS_ATTR,
2027 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002028 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002029 }
Paul Jakmab881c702010-11-23 16:35:42 +00002030 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002031}
2032
2033int stream_put_prefix (struct stream *, struct prefix *);
2034
2035/* Make attribute packet. */
2036bgp_size_t
2037bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2038 struct stream *s, struct attr *attr, struct prefix *p,
2039 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002040 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002041{
paulfe69a502005-09-10 16:55:02 +00002042 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002043 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002044 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002045 int send_as4_path = 0;
2046 int send_as4_aggregator = 0;
2047 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002048
2049 if (! bgp)
2050 bgp = bgp_get_default ();
2051
2052 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002053 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002054
2055 /* Origin attribute. */
2056 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2057 stream_putc (s, BGP_ATTR_ORIGIN);
2058 stream_putc (s, 1);
2059 stream_putc (s, attr->origin);
2060
2061 /* AS path attribute. */
2062
2063 /* If remote-peer is EBGP */
2064 if (peer_sort (peer) == BGP_PEER_EBGP
2065 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002066 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002067 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002068 {
2069 aspath = aspath_dup (attr->aspath);
2070
2071 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2072 {
2073 /* Strip the confed info, and then stuff our path CONFED_ID
2074 on the front */
2075 aspath = aspath_delete_confed_seq (aspath);
2076 aspath = aspath_add_seq (aspath, bgp->confed_id);
2077 }
2078 else
2079 {
2080 aspath = aspath_add_seq (aspath, peer->local_as);
2081 if (peer->change_local_as)
2082 aspath = aspath_add_seq (aspath, peer->change_local_as);
2083 }
2084 }
2085 else if (peer_sort (peer) == BGP_PEER_CONFED)
2086 {
2087 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2088 aspath = aspath_dup (attr->aspath);
2089 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2090 }
2091 else
2092 aspath = attr->aspath;
2093
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002094 /* If peer is not AS4 capable, then:
2095 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2096 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2097 * types are in it (i.e. exclude them if they are there)
2098 * AND do this only if there is at least one asnum > 65535 in the path!
2099 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2100 * all ASnums > 65535 to BGP_AS_TRANS
2101 */
paul718e3742002-12-13 20:15:29 +00002102
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002103 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2104 stream_putc (s, BGP_ATTR_AS_PATH);
2105 aspath_sizep = stream_get_endp (s);
2106 stream_putw (s, 0);
2107 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2108
2109 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2110 * in the path
2111 */
2112 if (!use32bit && aspath_has_as4 (aspath))
2113 send_as4_path = 1; /* we'll do this later, at the correct place */
2114
paul718e3742002-12-13 20:15:29 +00002115 /* Nexthop attribute. */
2116 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2117 {
2118 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2119 stream_putc (s, BGP_ATTR_NEXT_HOP);
2120 stream_putc (s, 4);
2121 if (safi == SAFI_MPLS_VPN)
2122 {
2123 if (attr->nexthop.s_addr == 0)
2124 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2125 else
2126 stream_put_ipv4 (s, attr->nexthop.s_addr);
2127 }
2128 else
2129 stream_put_ipv4 (s, attr->nexthop.s_addr);
2130 }
2131
2132 /* MED attribute. */
2133 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2134 {
2135 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2136 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2137 stream_putc (s, 4);
2138 stream_putl (s, attr->med);
2139 }
2140
2141 /* Local preference. */
2142 if (peer_sort (peer) == BGP_PEER_IBGP ||
2143 peer_sort (peer) == BGP_PEER_CONFED)
2144 {
2145 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2146 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2147 stream_putc (s, 4);
2148 stream_putl (s, attr->local_pref);
2149 }
2150
2151 /* Atomic aggregate. */
2152 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2153 {
2154 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2155 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2156 stream_putc (s, 0);
2157 }
2158
2159 /* Aggregator. */
2160 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2161 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002162 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002163
2164 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002165 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2166 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002167
2168 if (use32bit)
2169 {
2170 /* AS4 capable peer */
2171 stream_putc (s, 8);
2172 stream_putl (s, attr->extra->aggregator_as);
2173 }
2174 else
2175 {
2176 /* 2-byte AS peer */
2177 stream_putc (s, 6);
2178
2179 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2180 if ( attr->extra->aggregator_as > 65535 )
2181 {
2182 stream_putw (s, BGP_AS_TRANS);
2183
2184 /* we have to send AS4_AGGREGATOR, too.
2185 * we'll do that later in order to send attributes in ascending
2186 * order.
2187 */
2188 send_as4_aggregator = 1;
2189 }
2190 else
2191 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2192 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002193 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002194 }
2195
2196 /* Community attribute. */
2197 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2198 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2199 {
2200 if (attr->community->size * 4 > 255)
2201 {
2202 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2203 stream_putc (s, BGP_ATTR_COMMUNITIES);
2204 stream_putw (s, attr->community->size * 4);
2205 }
2206 else
2207 {
2208 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2209 stream_putc (s, BGP_ATTR_COMMUNITIES);
2210 stream_putc (s, attr->community->size * 4);
2211 }
2212 stream_put (s, attr->community->val, attr->community->size * 4);
2213 }
2214
2215 /* Route Reflector. */
2216 if (peer_sort (peer) == BGP_PEER_IBGP
2217 && from
2218 && peer_sort (from) == BGP_PEER_IBGP)
2219 {
2220 /* Originator ID. */
2221 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2222 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2223 stream_putc (s, 4);
2224
2225 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002226 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002227 else
2228 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002229
2230 /* Cluster list. */
2231 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2232 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2233
Paul Jakma9eda90c2007-08-30 13:36:17 +00002234 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002235 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002236 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002237 /* If this peer configuration's parent BGP has cluster_id. */
2238 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2239 stream_put_in_addr (s, &bgp->cluster_id);
2240 else
2241 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002242 stream_put (s, attr->extra->cluster->list,
2243 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002244 }
2245 else
2246 {
2247 stream_putc (s, 4);
2248 /* If this peer configuration's parent BGP has cluster_id. */
2249 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2250 stream_put_in_addr (s, &bgp->cluster_id);
2251 else
2252 stream_put_in_addr (s, &bgp->router_id);
2253 }
2254 }
2255
2256#ifdef HAVE_IPV6
2257 /* If p is IPv6 address put it into attribute. */
2258 if (p->family == AF_INET6)
2259 {
2260 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002261 struct attr_extra *attre = attr->extra;
2262
2263 assert (attr->extra);
2264
paul718e3742002-12-13 20:15:29 +00002265 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2266 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002267 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002268 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002269 stream_putw (s, AFI_IP6); /* AFI */
2270 stream_putc (s, safi); /* SAFI */
2271
Paul Jakmafb982c22007-05-04 20:15:47 +00002272 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002273
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 if (attre->mp_nexthop_len == 16)
2275 stream_put (s, &attre->mp_nexthop_global, 16);
2276 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002277 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002278 stream_put (s, &attre->mp_nexthop_global, 16);
2279 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002280 }
2281
2282 /* SNPA */
2283 stream_putc (s, 0);
2284
paul718e3742002-12-13 20:15:29 +00002285 /* Prefix write. */
2286 stream_put_prefix (s, p);
2287
2288 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002289 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002290 }
2291#endif /* HAVE_IPV6 */
2292
2293 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2294 {
2295 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002296
2297 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2298 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002299 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002300 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002301 stream_putw (s, AFI_IP); /* AFI */
2302 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2303
2304 stream_putc (s, 4);
2305 stream_put_ipv4 (s, attr->nexthop.s_addr);
2306
2307 /* SNPA */
2308 stream_putc (s, 0);
2309
paul718e3742002-12-13 20:15:29 +00002310 /* Prefix write. */
2311 stream_put_prefix (s, p);
2312
2313 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002314 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002315 }
2316
2317 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2318 {
2319 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002320
2321 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2322 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002323 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002324 stream_putc (s, 0); /* Length of this attribute. */
2325 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002326 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002327
2328 stream_putc (s, 12);
2329 stream_putl (s, 0);
2330 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002331 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002332
2333 /* SNPA */
2334 stream_putc (s, 0);
2335
paul718e3742002-12-13 20:15:29 +00002336 /* Tag, RD, Prefix write. */
2337 stream_putc (s, p->prefixlen + 88);
2338 stream_put (s, tag, 3);
2339 stream_put (s, prd->val, 8);
2340 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2341
2342 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002343 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002344 }
2345
2346 /* Extended Communities attribute. */
2347 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2348 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2349 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002350 struct attr_extra *attre = attr->extra;
2351
2352 assert (attre);
2353
2354 if (peer_sort (peer) == BGP_PEER_IBGP
2355 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002356 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002357 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002358 {
2359 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2360 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002361 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002362 }
2363 else
2364 {
2365 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2366 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002367 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002368 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002369 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002370 }
2371 else
2372 {
paul5228ad22004-06-04 17:58:18 +00002373 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002374 int tbit;
2375 int ecom_tr_size = 0;
2376 int i;
2377
Paul Jakmafb982c22007-05-04 20:15:47 +00002378 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002379 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002380 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002381 tbit = *pnt;
2382
2383 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2384 continue;
2385
2386 ecom_tr_size++;
2387 }
2388
2389 if (ecom_tr_size)
2390 {
2391 if (ecom_tr_size * 8 > 255)
2392 {
2393 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2394 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2395 stream_putw (s, ecom_tr_size * 8);
2396 }
2397 else
2398 {
2399 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2400 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2401 stream_putc (s, ecom_tr_size * 8);
2402 }
2403
Paul Jakmafb982c22007-05-04 20:15:47 +00002404 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002405 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002406 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002407 tbit = *pnt;
2408
2409 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2410 continue;
2411
2412 stream_put (s, pnt, 8);
2413 }
2414 }
paul718e3742002-12-13 20:15:29 +00002415 }
paul718e3742002-12-13 20:15:29 +00002416 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002417
2418 if ( send_as4_path )
2419 {
2420 /* If the peer is NOT As4 capable, AND */
2421 /* there are ASnums > 65535 in path THEN
2422 * give out AS4_PATH */
2423
2424 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2425 * path segments!
2426 * Hm, I wonder... confederation things *should* only be at
2427 * the beginning of an aspath, right? Then we should use
2428 * aspath_delete_confed_seq for this, because it is already
2429 * there! (JK)
2430 * Folks, talk to me: what is reasonable here!?
2431 */
2432 aspath = aspath_delete_confed_seq (aspath);
2433
2434 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2435 stream_putc (s, BGP_ATTR_AS4_PATH);
2436 aspath_sizep = stream_get_endp (s);
2437 stream_putw (s, 0);
2438 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2439 }
2440
2441 if (aspath != attr->aspath)
2442 aspath_free (aspath);
2443
2444 if ( send_as4_aggregator )
2445 {
2446 assert (attr->extra);
2447
2448 /* send AS4_AGGREGATOR, at this place */
2449 /* this section of code moved here in order to ensure the correct
2450 * *ascending* order of attributes
2451 */
2452 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2453 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2454 stream_putc (s, 8);
2455 stream_putl (s, attr->extra->aggregator_as);
2456 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2457 }
Paul Jakma41367172007-08-06 15:24:51 +00002458
paul718e3742002-12-13 20:15:29 +00002459 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002460 if (attr->extra && attr->extra->transit)
2461 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002462
2463 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002464 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002465}
2466
2467bgp_size_t
2468bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2469 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002470 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002471{
2472 unsigned long cp;
2473 unsigned long attrlen_pnt;
2474 bgp_size_t size;
2475
paul9985f832005-02-09 15:51:56 +00002476 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002477
2478 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2479 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2480
paul9985f832005-02-09 15:51:56 +00002481 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002482 stream_putc (s, 0); /* Length of this attribute. */
2483
2484 stream_putw (s, family2afi (p->family));
2485
2486 if (safi == SAFI_MPLS_VPN)
2487 {
2488 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002489 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002490
2491 /* prefix. */
2492 stream_putc (s, p->prefixlen + 88);
2493 stream_put (s, tag, 3);
2494 stream_put (s, prd->val, 8);
2495 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2496 }
2497 else
2498 {
2499 /* SAFI */
2500 stream_putc (s, safi);
2501
2502 /* prefix */
2503 stream_put_prefix (s, p);
2504 }
2505
2506 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002507 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002508 stream_putc_at (s, attrlen_pnt, size);
2509
paul9985f832005-02-09 15:51:56 +00002510 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002511}
2512
2513/* Initialization of attribute. */
2514void
paulfe69a502005-09-10 16:55:02 +00002515bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002516{
paul718e3742002-12-13 20:15:29 +00002517 aspath_init ();
2518 attrhash_init ();
2519 community_init ();
2520 ecommunity_init ();
2521 cluster_init ();
2522 transit_init ();
2523}
2524
Chris Caputo228da422009-07-18 05:44:03 +00002525void
2526bgp_attr_finish (void)
2527{
2528 aspath_finish ();
2529 attrhash_finish ();
2530 community_finish ();
2531 ecommunity_finish ();
2532 cluster_finish ();
2533 transit_finish ();
2534}
2535
paul718e3742002-12-13 20:15:29 +00002536/* Make attribute packet. */
2537void
paula3845922003-10-18 01:30:50 +00002538bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2539 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002540{
2541 unsigned long cp;
2542 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002543 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002544 struct aspath *aspath;
2545
2546 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002547 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002548
2549 /* Place holder of length. */
2550 stream_putw (s, 0);
2551
2552 /* Origin attribute. */
2553 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2554 stream_putc (s, BGP_ATTR_ORIGIN);
2555 stream_putc (s, 1);
2556 stream_putc (s, attr->origin);
2557
2558 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002559
2560 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2561 stream_putc (s, BGP_ATTR_AS_PATH);
2562 aspath_lenp = stream_get_endp (s);
2563 stream_putw (s, 0);
2564
2565 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002566
2567 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002568 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2569 if(prefix != NULL
2570#ifdef HAVE_IPV6
2571 && prefix->family != AF_INET6
2572#endif /* HAVE_IPV6 */
2573 )
2574 {
2575 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2576 stream_putc (s, BGP_ATTR_NEXT_HOP);
2577 stream_putc (s, 4);
2578 stream_put_ipv4 (s, attr->nexthop.s_addr);
2579 }
paul718e3742002-12-13 20:15:29 +00002580
2581 /* MED attribute. */
2582 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2583 {
2584 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2585 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2586 stream_putc (s, 4);
2587 stream_putl (s, attr->med);
2588 }
2589
2590 /* Local preference. */
2591 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2592 {
2593 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2594 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2595 stream_putc (s, 4);
2596 stream_putl (s, attr->local_pref);
2597 }
2598
2599 /* Atomic aggregate. */
2600 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2601 {
2602 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2603 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2604 stream_putc (s, 0);
2605 }
2606
2607 /* Aggregator. */
2608 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2609 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002610 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002611 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2612 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002613 stream_putc (s, 8);
2614 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002615 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002616 }
2617
2618 /* Community attribute. */
2619 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2620 {
2621 if (attr->community->size * 4 > 255)
2622 {
2623 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2624 stream_putc (s, BGP_ATTR_COMMUNITIES);
2625 stream_putw (s, attr->community->size * 4);
2626 }
2627 else
2628 {
2629 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2630 stream_putc (s, BGP_ATTR_COMMUNITIES);
2631 stream_putc (s, attr->community->size * 4);
2632 }
2633 stream_put (s, attr->community->val, attr->community->size * 4);
2634 }
2635
paula3845922003-10-18 01:30:50 +00002636#ifdef HAVE_IPV6
2637 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002638 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2639 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002640 {
2641 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002642 struct attr_extra *attre = attr->extra;
2643
paula3845922003-10-18 01:30:50 +00002644 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2645 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002646 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002647
2648 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002649 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002650 stream_putw(s, AFI_IP6); /* AFI */
2651 stream_putc(s, SAFI_UNICAST); /* SAFI */
2652
2653 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002654 stream_putc(s, attre->mp_nexthop_len);
2655 stream_put(s, &attre->mp_nexthop_global, 16);
2656 if (attre->mp_nexthop_len == 32)
2657 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002658
2659 /* SNPA */
2660 stream_putc(s, 0);
2661
2662 /* Prefix */
2663 stream_put_prefix(s, prefix);
2664
2665 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002666 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002667 }
2668#endif /* HAVE_IPV6 */
2669
paul718e3742002-12-13 20:15:29 +00002670 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002671 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002672 stream_putw_at (s, cp, len);
2673}