blob: b63ac4c804445abe018abb2ef852c42eb66a0081 [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]);
Denis Ovsienkoafcb7672011-10-23 22:32:44 +040066
67static const struct message attr_flag_str[] =
68{
69 { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
70 { BGP_ATTR_FLAG_TRANS, "Transitive" },
71 { BGP_ATTR_FLAG_PARTIAL, "Partial" },
72 /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
73 { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
74};
75static const size_t attr_flag_str_max =
76 sizeof (attr_flag_str) / sizeof (attr_flag_str[0]);
paul718e3742002-12-13 20:15:29 +000077
Stephen Hemminger9bddac42009-05-15 09:59:51 -070078static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000079
paul94f2b392005-06-28 12:44:16 +000080static void *
Paul Jakma923de652007-04-29 18:25:17 +000081cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000082{
Paul Jakma923de652007-04-29 18:25:17 +000083 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000084 struct cluster_list *cluster;
85
86 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
87 cluster->length = val->length;
88
89 if (cluster->length)
90 {
91 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
92 memcpy (cluster->list, val->list, val->length);
93 }
94 else
95 cluster->list = NULL;
96
97 cluster->refcnt = 0;
98
99 return cluster;
100}
101
102/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +0000103static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +0000104cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +0000105{
106 struct cluster_list tmp;
107 struct cluster_list *cluster;
108
109 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +0000110 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000111
112 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
113 cluster->refcnt++;
114 return cluster;
115}
116
117int
118cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
119{
120 int i;
121
122 for (i = 0; i < cluster->length / 4; i++)
123 if (cluster->list[i].s_addr == originator.s_addr)
124 return 1;
125 return 0;
126}
127
paul94f2b392005-06-28 12:44:16 +0000128static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000129cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000130{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700131 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000132
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700133 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000134}
135
paul94f2b392005-06-28 12:44:16 +0000136static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100137cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000138{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 const struct cluster_list * cluster1 = p1;
140 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000141
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100142 return (cluster1->length == cluster2->length &&
143 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000144}
145
paul94f2b392005-06-28 12:44:16 +0000146static void
paul718e3742002-12-13 20:15:29 +0000147cluster_free (struct cluster_list *cluster)
148{
149 if (cluster->list)
150 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
151 XFREE (MTYPE_CLUSTER, cluster);
152}
153
Chris Caputo228da422009-07-18 05:44:03 +0000154#if 0
paul94f2b392005-06-28 12:44:16 +0000155static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000156cluster_dup (struct cluster_list *cluster)
157{
158 struct cluster_list *new;
159
Stephen Hemminger393deb92008-08-18 14:13:29 -0700160 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000161 new->length = cluster->length;
162
163 if (cluster->length)
164 {
165 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
166 memcpy (new->list, cluster->list, cluster->length);
167 }
168 else
169 new->list = NULL;
170
171 return new;
172}
Chris Caputo228da422009-07-18 05:44:03 +0000173#endif
paul718e3742002-12-13 20:15:29 +0000174
paul94f2b392005-06-28 12:44:16 +0000175static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000176cluster_intern (struct cluster_list *cluster)
177{
178 struct cluster_list *find;
179
180 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
181 find->refcnt++;
182
183 return find;
184}
185
186void
187cluster_unintern (struct cluster_list *cluster)
188{
paul718e3742002-12-13 20:15:29 +0000189 if (cluster->refcnt)
190 cluster->refcnt--;
191
192 if (cluster->refcnt == 0)
193 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400194 hash_release (cluster_hash, cluster);
paul718e3742002-12-13 20:15:29 +0000195 cluster_free (cluster);
196 }
197}
198
paul94f2b392005-06-28 12:44:16 +0000199static void
200cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000201{
202 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
203}
Chris Caputo228da422009-07-18 05:44:03 +0000204
205static void
206cluster_finish (void)
207{
208 hash_free (cluster_hash);
209 cluster_hash = NULL;
210}
paul718e3742002-12-13 20:15:29 +0000211
212/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700213static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000214
paul94f2b392005-06-28 12:44:16 +0000215static void
paul718e3742002-12-13 20:15:29 +0000216transit_free (struct transit *transit)
217{
218 if (transit->val)
219 XFREE (MTYPE_TRANSIT_VAL, transit->val);
220 XFREE (MTYPE_TRANSIT, transit);
221}
222
Paul Jakma923de652007-04-29 18:25:17 +0000223
paul94f2b392005-06-28 12:44:16 +0000224static void *
Paul Jakma923de652007-04-29 18:25:17 +0000225transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000226{
227 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000228 return p;
paul718e3742002-12-13 20:15:29 +0000229}
230
paul94f2b392005-06-28 12:44:16 +0000231static struct transit *
paul718e3742002-12-13 20:15:29 +0000232transit_intern (struct transit *transit)
233{
234 struct transit *find;
235
236 find = hash_get (transit_hash, transit, transit_hash_alloc);
237 if (find != transit)
238 transit_free (transit);
239 find->refcnt++;
240
241 return find;
242}
243
244void
245transit_unintern (struct transit *transit)
246{
paul718e3742002-12-13 20:15:29 +0000247 if (transit->refcnt)
248 transit->refcnt--;
249
250 if (transit->refcnt == 0)
251 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400252 hash_release (transit_hash, transit);
paul718e3742002-12-13 20:15:29 +0000253 transit_free (transit);
254 }
255}
256
paul94f2b392005-06-28 12:44:16 +0000257static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000258transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000259{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700260 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000261
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700262 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000263}
264
paul94f2b392005-06-28 12:44:16 +0000265static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100266transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000267{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100268 const struct transit * transit1 = p1;
269 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000270
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100271 return (transit1->length == transit2->length &&
272 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000273}
274
paul94f2b392005-06-28 12:44:16 +0000275static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800276transit_init (void)
paul718e3742002-12-13 20:15:29 +0000277{
278 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
279}
Chris Caputo228da422009-07-18 05:44:03 +0000280
281static void
282transit_finish (void)
283{
284 hash_free (transit_hash);
285 transit_hash = NULL;
286}
paul718e3742002-12-13 20:15:29 +0000287
288/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700289static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000290
Paul Jakmafb982c22007-05-04 20:15:47 +0000291static struct attr_extra *
292bgp_attr_extra_new (void)
293{
294 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
295}
296
297void
298bgp_attr_extra_free (struct attr *attr)
299{
300 if (attr->extra)
301 {
302 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
303 attr->extra = NULL;
304 }
305}
306
307struct attr_extra *
308bgp_attr_extra_get (struct attr *attr)
309{
310 if (!attr->extra)
311 attr->extra = bgp_attr_extra_new();
312 return attr->extra;
313}
314
315/* Shallow copy of an attribute
316 * Though, not so shallow that it doesn't copy the contents
317 * of the attr_extra pointed to by 'extra'
318 */
319void
320bgp_attr_dup (struct attr *new, struct attr *orig)
321{
322 *new = *orig;
323 if (orig->extra)
324 {
325 new->extra = bgp_attr_extra_new();
326 *new->extra = *orig->extra;
327 }
328}
329
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000330unsigned long int
331attr_count (void)
332{
333 return attrhash->count;
334}
335
336unsigned long int
337attr_unknown_count (void)
338{
339 return transit_hash->count;
340}
341
paul718e3742002-12-13 20:15:29 +0000342unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000343attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000344{
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000345 const struct attr *attr = (struct attr *) p;
346 const struct attr_extra *extra = attr->extra;
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700347 uint32_t key = 0;
348#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000349
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700350 MIX(attr->origin);
351 MIX(attr->nexthop.s_addr);
352 MIX(attr->med);
353 MIX(attr->local_pref);
354
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000355 key += attr->origin;
356 key += attr->nexthop.s_addr;
357 key += attr->med;
358 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000359
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000360 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000361 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000362 MIX(extra->aggregator_as);
363 MIX(extra->aggregator_addr.s_addr);
364 MIX(extra->weight);
365 MIX(extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000366 }
367
paul718e3742002-12-13 20:15:29 +0000368 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700369 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000370 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700371 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000372
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000373 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000374 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000375 if (extra->ecommunity)
376 MIX(ecommunity_hash_make (extra->ecommunity));
377 if (extra->cluster)
378 MIX(cluster_hash_key_make (extra->cluster));
379 if (extra->transit)
380 MIX(transit_hash_key_make (extra->transit));
paul718e3742002-12-13 20:15:29 +0000381
382#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000383 MIX(extra->mp_nexthop_len);
384 key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
385 key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000386#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000387 }
paul718e3742002-12-13 20:15:29 +0000388
389 return key;
390}
391
392int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100393attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000394{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100395 const struct attr * attr1 = p1;
396 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000397
paul718e3742002-12-13 20:15:29 +0000398 if (attr1->flag == attr2->flag
399 && attr1->origin == attr2->origin
400 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000401 && attr1->aspath == attr2->aspath
402 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000403 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000404 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000405 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100406 const struct attr_extra *ae1 = attr1->extra;
407 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000408
409 if (ae1 && ae2
410 && ae1->aggregator_as == ae2->aggregator_as
411 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
412 && ae1->weight == ae2->weight
413#ifdef HAVE_IPV6
414 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
415 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
416 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
417#endif /* HAVE_IPV6 */
418 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
419 && ae1->ecommunity == ae2->ecommunity
420 && ae1->cluster == ae2->cluster
421 && ae1->transit == ae2->transit)
422 return 1;
423 else if (ae1 || ae2)
424 return 0;
425 /* neither attribute has extra attributes, so they're same */
426 return 1;
427 }
paul718e3742002-12-13 20:15:29 +0000428 else
429 return 0;
430}
431
paul94f2b392005-06-28 12:44:16 +0000432static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100433attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000434{
435 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
436}
437
paul94f2b392005-06-28 12:44:16 +0000438static void
Chris Caputo228da422009-07-18 05:44:03 +0000439attrhash_finish (void)
440{
441 hash_free (attrhash);
442 attrhash = NULL;
443}
444
445static void
paul718e3742002-12-13 20:15:29 +0000446attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
447{
448 struct attr *attr = backet->data;
449
450 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
451 inet_ntoa (attr->nexthop), VTY_NEWLINE);
452}
453
454void
455attr_show_all (struct vty *vty)
456{
457 hash_iterate (attrhash,
458 (void (*)(struct hash_backet *, void *))
459 attr_show_all_iterator,
460 vty);
461}
462
paul94f2b392005-06-28 12:44:16 +0000463static void *
Paul Jakma923de652007-04-29 18:25:17 +0000464bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000465{
Paul Jakma923de652007-04-29 18:25:17 +0000466 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000467 struct attr *attr;
468
469 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
470 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000471 if (val->extra)
472 {
473 attr->extra = bgp_attr_extra_new ();
474 *attr->extra = *val->extra;
475 }
paul718e3742002-12-13 20:15:29 +0000476 attr->refcnt = 0;
477 return attr;
478}
479
480/* Internet argument attribute. */
481struct attr *
482bgp_attr_intern (struct attr *attr)
483{
484 struct attr *find;
485
486 /* Intern referenced strucutre. */
487 if (attr->aspath)
488 {
489 if (! attr->aspath->refcnt)
490 attr->aspath = aspath_intern (attr->aspath);
491 else
492 attr->aspath->refcnt++;
493 }
494 if (attr->community)
495 {
496 if (! attr->community->refcnt)
497 attr->community = community_intern (attr->community);
498 else
499 attr->community->refcnt++;
500 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000501 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000502 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000503 struct attr_extra *attre = attr->extra;
504
505 if (attre->ecommunity)
506 {
507 if (! attre->ecommunity->refcnt)
508 attre->ecommunity = ecommunity_intern (attre->ecommunity);
509 else
510 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000511
Paul Jakmafb982c22007-05-04 20:15:47 +0000512 }
513 if (attre->cluster)
514 {
515 if (! attre->cluster->refcnt)
516 attre->cluster = cluster_intern (attre->cluster);
517 else
518 attre->cluster->refcnt++;
519 }
520 if (attre->transit)
521 {
522 if (! attre->transit->refcnt)
523 attre->transit = transit_intern (attre->transit);
524 else
525 attre->transit->refcnt++;
526 }
paul718e3742002-12-13 20:15:29 +0000527 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000528
paul718e3742002-12-13 20:15:29 +0000529 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
530 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000531
paul718e3742002-12-13 20:15:29 +0000532 return find;
533}
534
Paul Jakma03e214c2007-04-29 18:31:07 +0000535
paul718e3742002-12-13 20:15:29 +0000536/* Make network statement's attribute. */
537struct attr *
538bgp_attr_default_set (struct attr *attr, u_char origin)
539{
540 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000541 bgp_attr_extra_get (attr);
542
paul718e3742002-12-13 20:15:29 +0000543 attr->origin = origin;
544 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
545 attr->aspath = aspath_empty ();
546 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000547 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000548 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
549#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000550 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000551#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000552
paul718e3742002-12-13 20:15:29 +0000553 return attr;
554}
555
Paul Jakma03e214c2007-04-29 18:31:07 +0000556
paul718e3742002-12-13 20:15:29 +0000557/* Make network statement's attribute. */
558struct attr *
559bgp_attr_default_intern (u_char origin)
560{
561 struct attr attr;
562 struct attr *new;
Jorge Boncompte [DTI2]e16a4132012-05-07 16:52:57 +0000563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000565
566 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000567 bgp_attr_extra_free (&attr);
568
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000569 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000570 return new;
571}
572
573struct attr *
574bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
575 struct aspath *aspath,
576 struct community *community, int as_set)
577{
578 struct attr attr;
579 struct attr *new;
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000580 struct attr_extra attre;
paul718e3742002-12-13 20:15:29 +0000581
582 memset (&attr, 0, sizeof (struct attr));
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000583 memset (&attre, 0, sizeof (struct attr_extra));
584 attr.extra = &attre;
585
paul718e3742002-12-13 20:15:29 +0000586 /* Origin attribute. */
587 attr.origin = origin;
588 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
589
590 /* AS path attribute. */
591 if (aspath)
592 attr.aspath = aspath_intern (aspath);
593 else
594 attr.aspath = aspath_empty ();
595 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
596
597 /* Next hop attribute. */
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
599
600 if (community)
601 {
602 attr.community = community;
603 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
604 }
605
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000606 attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000607#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000608 attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000609#endif
610 if (! as_set)
611 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
612 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
613 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000614 attre.aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000615 else
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000616 attre.aggregator_as = bgp->as;
617 attre.aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000618
619 new = bgp_attr_intern (&attr);
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000620
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000621 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000622 return new;
623}
624
Paul Jakmab881c702010-11-23 16:35:42 +0000625/* Unintern just the sub-components of the attr, but not the attr */
626void
627bgp_attr_unintern_sub (struct attr *attr)
628{
629 /* aspath refcount shoud be decrement. */
630 if (attr->aspath)
631 aspath_unintern (&attr->aspath);
632 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
633
634 if (attr->community)
635 community_unintern (&attr->community);
636 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
637
638 if (attr->extra)
639 {
640 if (attr->extra->ecommunity)
641 ecommunity_unintern (&attr->extra->ecommunity);
642 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
643
644 if (attr->extra->cluster)
645 cluster_unintern (attr->extra->cluster);
646 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
647
648 if (attr->extra->transit)
649 transit_unintern (attr->extra->transit);
650 }
651}
652
paul718e3742002-12-13 20:15:29 +0000653/* Free bgp attribute and aspath. */
654void
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000655bgp_attr_unintern (struct attr **pattr)
paul718e3742002-12-13 20:15:29 +0000656{
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000657 struct attr *attr = *pattr;
paul718e3742002-12-13 20:15:29 +0000658 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000659 struct attr tmp;
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000660 struct attr_extra tmp_extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661
paul718e3742002-12-13 20:15:29 +0000662 /* Decrement attribute reference. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000663 attr->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000664
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000665 tmp = *attr;
Paul Jakmab881c702010-11-23 16:35:42 +0000666
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000667 if (attr->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000668 {
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000669 tmp.extra = &tmp_extra;
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000670 memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672
paul718e3742002-12-13 20:15:29 +0000673 /* If reference becomes zero then free attribute object. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000674 if (attr->refcnt == 0)
675 {
676 ret = hash_release (attrhash, attr);
paul718e3742002-12-13 20:15:29 +0000677 assert (ret != NULL);
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000678 bgp_attr_extra_free (attr);
679 XFREE (MTYPE_ATTR, attr);
680 *pattr = NULL;
paul718e3742002-12-13 20:15:29 +0000681 }
682
Paul Jakmab881c702010-11-23 16:35:42 +0000683 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000684}
685
686void
687bgp_attr_flush (struct attr *attr)
688{
689 if (attr->aspath && ! attr->aspath->refcnt)
690 aspath_free (attr->aspath);
691 if (attr->community && ! attr->community->refcnt)
692 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000693 if (attr->extra)
694 {
695 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000696
Paul Jakmafb982c22007-05-04 20:15:47 +0000697 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000698 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000699 if (attre->cluster && ! attre->cluster->refcnt)
700 cluster_free (attre->cluster);
701 if (attre->transit && ! attre->transit->refcnt)
702 transit_free (attre->transit);
703 }
paul718e3742002-12-13 20:15:29 +0000704}
705
Paul Jakmab881c702010-11-23 16:35:42 +0000706/* Implement draft-scudder-idr-optional-transitive behaviour and
707 * avoid resetting sessions for malformed attributes which are
708 * are partial/optional and hence where the error likely was not
709 * introduced by the sending neighbour.
710 */
711static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000712bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
713 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000714{
Paul Jakma835315b2012-01-18 12:28:30 +0000715 struct peer *const peer = args->peer;
716 const u_int8_t flags = args->flags;
717 /* startp and length must be special-cased, as whether or not to
718 * send the attribute data with the NOTIFY depends on the error,
719 * the caller therefore signals this with the seperate length argument
720 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000721 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000722
Paul Jakmab881c702010-11-23 16:35:42 +0000723 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000724 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000725 {
726 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000727 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000728 return BGP_ATTR_PARSE_ERROR;
729
730 }
731
Paul Jakmabd471fe2012-03-15 11:30:00 +0000732 /* Adjust the stream getp to the end of the attribute, in case we can
733 * still proceed but the caller hasn't read all the attribute.
734 */
735 stream_set_getp (BGP_INPUT (peer),
736 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
737 + args->total);
738
Paul Jakma835315b2012-01-18 12:28:30 +0000739 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100740 /* where an attribute is relatively inconsequential, e.g. it does not
741 * affect route selection, and can be safely ignored, then any such
742 * attributes which are malformed should just be ignored and the route
743 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000744 */
745 case BGP_ATTR_AS4_AGGREGATOR:
746 case BGP_ATTR_AGGREGATOR:
747 case BGP_ATTR_ATOMIC_AGGREGATE:
748 return BGP_ATTR_PARSE_PROCEED;
749
750 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100751 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000752 */
753 case BGP_ATTR_ORIGIN:
754 case BGP_ATTR_AS_PATH:
755 case BGP_ATTR_NEXT_HOP:
756 case BGP_ATTR_MULTI_EXIT_DISC:
757 case BGP_ATTR_LOCAL_PREF:
758 case BGP_ATTR_COMMUNITIES:
759 case BGP_ATTR_ORIGINATOR_ID:
760 case BGP_ATTR_CLUSTER_LIST:
761 case BGP_ATTR_MP_REACH_NLRI:
762 case BGP_ATTR_MP_UNREACH_NLRI:
763 case BGP_ATTR_EXT_COMMUNITIES:
764 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000765 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000766 return BGP_ATTR_PARSE_ERROR;
767 }
768
769 /* Partial optional attributes that are malformed should not cause
770 * the whole session to be reset. Instead treat it as a withdrawal
771 * of the routes, if possible.
772 */
Paul Jakma835315b2012-01-18 12:28:30 +0000773 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
774 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
775 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000776 return BGP_ATTR_PARSE_WITHDRAW;
777
778 /* default to reset */
779 return BGP_ATTR_PARSE_ERROR;
780}
781
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400782/* Find out what is wrong with the path attribute flag bits and log the error.
783 "Flag bits" here stand for Optional, Transitive and Partial, but not for
784 Extended Length. Checking O/T/P bits at once implies, that the attribute
785 being diagnosed is defined by RFC as either a "well-known" or an "optional,
786 non-transitive" attribute. */
787static void
Paul Jakma835315b2012-01-18 12:28:30 +0000788bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
789 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400790)
791{
792 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000793 u_char real_flags = args->flags;
794 const u_int8_t attr_code = args->type;
795
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400796 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
797 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
798 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
799 if
800 (
801 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
802 CHECK_FLAG (real_flags, attr_flag_str[i].key)
803 )
804 {
Paul Jakma835315b2012-01-18 12:28:30 +0000805 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400806 LOOKUP (attr_str, attr_code),
807 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
808 attr_flag_str[i].str);
809 seen = 1;
810 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100811 if (!seen)
812 {
813 zlog (args->peer->log, LOG_DEBUG,
814 "Strange, %s called for attr %s, but no problem found with flags"
815 " (real flags 0x%x, desired 0x%x)",
816 __func__, LOOKUP (attr_str, attr_code),
817 real_flags, desired_flags);
818 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400819}
820
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000821/* Required flags for attributes. EXTLEN will be masked off when testing,
822 * as will PARTIAL for optional+transitive attributes.
823 */
824const u_int8_t attr_flags_values [] = {
825 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
826 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
827 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
828 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
829 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
830 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
831 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
832 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
833 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
834 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
835 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
836 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
837 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
838 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
839 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
840};
841static const size_t attr_flags_values_max =
842 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
843
844static int
Paul Jakma835315b2012-01-18 12:28:30 +0000845bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000846{
847 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000848 const u_int8_t flags = args->flags;
849 const u_int8_t attr_code = args->type;
850 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000851
852 /* there may be attributes we don't know about */
853 if (attr_code > attr_flags_values_max)
854 return 0;
855 if (attr_flags_values[attr_code] == 0)
856 return 0;
857
858 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
859 * 1."
860 */
861 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
862 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
863 {
864 zlog (peer->log, LOG_ERR,
865 "%s well-known attributes must have transitive flag set (%x)",
866 LOOKUP (attr_str, attr_code), flags);
867 return 1;
868 }
869
870 /* "For well-known attributes and for optional non-transitive attributes,
871 * the Partial bit MUST be set to 0."
872 */
873 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
874 {
875 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
876 {
877 zlog (peer->log, LOG_ERR,
878 "%s well-known attribute "
879 "must NOT have the partial flag set (%x)",
880 LOOKUP (attr_str, attr_code), flags);
881 return 1;
882 }
883 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
884 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
885 {
886 zlog (peer->log, LOG_ERR,
887 "%s optional + transitive attribute "
888 "must NOT have the partial flag set (%x)",
889 LOOKUP (attr_str, attr_code), flags);
890 return 1;
891 }
892 }
893
894 /* Optional transitive attributes may go through speakers that don't
895 * reocgnise them and set the Partial bit.
896 */
897 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
898 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
899 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
900
Paul Jakma683f2b82012-03-23 14:58:45 +0000901 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000902 == attr_flags_values[attr_code])
903 return 0;
904
Paul Jakma835315b2012-01-18 12:28:30 +0000905 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000906 return 1;
907}
908
paul718e3742002-12-13 20:15:29 +0000909/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000910static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000911bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000912{
Paul Jakma835315b2012-01-18 12:28:30 +0000913 struct peer *const peer = args->peer;
914 struct attr *const attr = args->attr;
915 const bgp_size_t length = args->length;
916
paul718e3742002-12-13 20:15:29 +0000917 /* If any recognized attribute has Attribute Length that conflicts
918 with the expected length (based on the attribute type code), then
919 the Error Subcode is set to Attribute Length Error. The Data
920 field contains the erroneous attribute (type, length and
921 value). */
922 if (length != 1)
923 {
924 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
925 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000926 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000927 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000928 args->total);
paul718e3742002-12-13 20:15:29 +0000929 }
930
931 /* Fetch origin attribute. */
932 attr->origin = stream_getc (BGP_INPUT (peer));
933
934 /* If the ORIGIN attribute has an undefined value, then the Error
935 Subcode is set to Invalid Origin Attribute. The Data field
936 contains the unrecognized attribute (type, length and value). */
937 if ((attr->origin != BGP_ORIGIN_IGP)
938 && (attr->origin != BGP_ORIGIN_EGP)
939 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
940 {
941 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
942 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000943 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000944 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000945 args->total);
paul718e3742002-12-13 20:15:29 +0000946 }
947
948 /* Set oring attribute flag. */
949 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
950
951 return 0;
952}
Paul Jakmaab005292010-11-27 22:48:34 +0000953
954/* Parse AS path information. This function is wrapper of
955 aspath_parse. */
956static int
Paul Jakma835315b2012-01-18 12:28:30 +0000957bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000958{
Paul Jakma835315b2012-01-18 12:28:30 +0000959 struct attr *const attr = args->attr;
960 struct peer *const peer = args->peer;
961 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000962
Paul Jakmaab005292010-11-27 22:48:34 +0000963 /*
964 * peer with AS4 => will get 4Byte ASnums
965 * otherwise, will get 16 Bit
966 */
967 attr->aspath = aspath_parse (peer->ibuf, length,
968 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
969
970 /* In case of IBGP, length will be zero. */
971 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000972 {
Paul Jakmab881c702010-11-23 16:35:42 +0000973 zlog (peer->log, LOG_ERR,
974 "Malformed AS path from %s, length is %d",
975 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000976 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000977 }
Chris Hallcddb8112010-08-09 22:31:37 +0400978
Paul Jakmaab005292010-11-27 22:48:34 +0000979 /* Set aspath attribute flag. */
980 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000981
Paul Jakmab881c702010-11-23 16:35:42 +0000982 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000983}
984
Paul Jakmab881c702010-11-23 16:35:42 +0000985static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000986bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000987{
988 /* These checks were part of bgp_attr_aspath, but with
989 * as4 we should to check aspath things when
990 * aspath synthesizing with as4_path has already taken place.
991 * Otherwise we check ASPATH and use the synthesized thing, and that is
992 * not right.
993 * So do the checks later, i.e. here
994 */
995 struct bgp *bgp = peer->bgp;
996 struct aspath *aspath;
997
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300998 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000999 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1000 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001001 {
1002 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001003 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1004 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1005 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001006 }
1007
paul718e3742002-12-13 20:15:29 +00001008 /* First AS check for EBGP. */
1009 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1010 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001011 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001012 && ! aspath_firstas_check (attr->aspath, peer->as))
1013 {
1014 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001015 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001016 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1017 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1018 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001019 }
1020 }
1021
1022 /* local-as prepend */
1023 if (peer->change_local_as &&
1024 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1025 {
1026 aspath = aspath_dup (attr->aspath);
1027 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001028 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001029 attr->aspath = aspath_intern (aspath);
1030 }
1031
Paul Jakmab881c702010-11-23 16:35:42 +00001032 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001033}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001034
Paul Jakmaab005292010-11-27 22:48:34 +00001035/* Parse AS4 path information. This function is another wrapper of
1036 aspath_parse. */
1037static int
Paul Jakma835315b2012-01-18 12:28:30 +00001038bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001039{
Paul Jakma835315b2012-01-18 12:28:30 +00001040 struct peer *const peer = args->peer;
1041 struct attr *const attr = args->attr;
1042 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001043
Paul Jakmaab005292010-11-27 22:48:34 +00001044 *as4_path = aspath_parse (peer->ibuf, length, 1);
1045
Paul Jakmab881c702010-11-23 16:35:42 +00001046 /* In case of IBGP, length will be zero. */
1047 if (!*as4_path)
1048 {
1049 zlog (peer->log, LOG_ERR,
1050 "Malformed AS4 path from %s, length is %d",
1051 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001052 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001053 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001054 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001055 }
1056
Paul Jakmaab005292010-11-27 22:48:34 +00001057 /* Set aspath attribute flag. */
1058 if (as4_path)
1059 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1060
Paul Jakmab881c702010-11-23 16:35:42 +00001061 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001062}
1063
paul718e3742002-12-13 20:15:29 +00001064/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001065static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001066bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001067{
Paul Jakma835315b2012-01-18 12:28:30 +00001068 struct peer *const peer = args->peer;
1069 struct attr *const attr = args->attr;
1070 const bgp_size_t length = args->length;
1071
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001072 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001073
paul718e3742002-12-13 20:15:29 +00001074 /* Check nexthop attribute length. */
1075 if (length != 4)
1076 {
1077 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1078 length);
1079
Paul Jakma835315b2012-01-18 12:28:30 +00001080 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001081 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001082 args->total);
paul718e3742002-12-13 20:15:29 +00001083 }
1084
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001085 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1086 attribute must result in a NOTIFICATION message (this is implemented below).
1087 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1088 logged locally (this is implemented somewhere else). The UPDATE message
1089 gets ignored in any of these cases. */
1090 nexthop_n = stream_get_ipv4 (peer->ibuf);
1091 nexthop_h = ntohl (nexthop_n);
1092 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1093 {
1094 char buf[INET_ADDRSTRLEN];
1095 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1096 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001097 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001098 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001099 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001100 }
1101
1102 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001103 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1104
Paul Jakmab881c702010-11-23 16:35:42 +00001105 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001106}
1107
1108/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001109static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001110bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001111{
Paul Jakma835315b2012-01-18 12:28:30 +00001112 struct peer *const peer = args->peer;
1113 struct attr *const attr = args->attr;
1114 const bgp_size_t length = args->length;
1115
paul718e3742002-12-13 20:15:29 +00001116 /* Length check. */
1117 if (length != 4)
1118 {
1119 zlog (peer->log, LOG_ERR,
1120 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001121
Paul Jakma835315b2012-01-18 12:28:30 +00001122 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001123 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001124 args->total);
paul718e3742002-12-13 20:15:29 +00001125 }
1126
1127 attr->med = stream_getl (peer->ibuf);
1128
1129 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1130
Paul Jakmab881c702010-11-23 16:35:42 +00001131 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001132}
1133
1134/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001135static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001136bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001137{
Paul Jakma835315b2012-01-18 12:28:30 +00001138 struct peer *const peer = args->peer;
1139 struct attr *const attr = args->attr;
1140 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001141
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001142 /* Length check. */
1143 if (length != 4)
1144 {
Paul Jakma835315b2012-01-18 12:28:30 +00001145 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1146 length);
1147 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001148 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001149 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001150 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001151
paul718e3742002-12-13 20:15:29 +00001152 /* If it is contained in an UPDATE message that is received from an
1153 external peer, then this attribute MUST be ignored by the
1154 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001155 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001156 {
paul9985f832005-02-09 15:51:56 +00001157 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001158 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001159 }
1160
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001161 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001162
1163 /* Set atomic aggregate flag. */
1164 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1165
Paul Jakmab881c702010-11-23 16:35:42 +00001166 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001167}
1168
1169/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001170static int
Paul Jakma835315b2012-01-18 12:28:30 +00001171bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001172{
Paul Jakma835315b2012-01-18 12:28:30 +00001173 struct peer *const peer = args->peer;
1174 struct attr *const attr = args->attr;
1175 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001176
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001177 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001178 if (length != 0)
1179 {
Paul Jakma835315b2012-01-18 12:28:30 +00001180 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1181 length);
1182 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001183 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001184 args->total);
paul718e3742002-12-13 20:15:29 +00001185 }
1186
1187 /* Set atomic aggregate flag. */
1188 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1189
Paul Jakmab881c702010-11-23 16:35:42 +00001190 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001191}
1192
1193/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001194static int
Paul Jakma835315b2012-01-18 12:28:30 +00001195bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001196{
Paul Jakma835315b2012-01-18 12:28:30 +00001197 struct peer *const peer = args->peer;
1198 struct attr *const attr = args->attr;
1199 const bgp_size_t length = args->length;
1200
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001201 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001202 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001203
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001204 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001205 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001206 wantedlen = 8;
1207
1208 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001209 {
Paul Jakma835315b2012-01-18 12:28:30 +00001210 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1211 wantedlen, length);
1212 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001213 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001214 args->total);
paul718e3742002-12-13 20:15:29 +00001215 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001216
1217 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1218 attre->aggregator_as = stream_getl (peer->ibuf);
1219 else
1220 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001221 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001222
1223 /* Set atomic aggregate flag. */
1224 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1225
Paul Jakmab881c702010-11-23 16:35:42 +00001226 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001227}
1228
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001229/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001230static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001231bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1232 as_t *as4_aggregator_as,
1233 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001234{
Paul Jakma835315b2012-01-18 12:28:30 +00001235 struct peer *const peer = args->peer;
1236 struct attr *const attr = args->attr;
1237 const bgp_size_t length = args->length;
1238
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001239 if (length != 8)
1240 {
Paul Jakma835315b2012-01-18 12:28:30 +00001241 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1242 length);
1243 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001244 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001245 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001246 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001247
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001248 *as4_aggregator_as = stream_getl (peer->ibuf);
1249 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1250
1251 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1252
Paul Jakmab881c702010-11-23 16:35:42 +00001253 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001254}
1255
1256/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1257 */
Paul Jakmab881c702010-11-23 16:35:42 +00001258static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001259bgp_attr_munge_as4_attrs (struct peer *const peer,
1260 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001261 struct aspath *as4_path, as_t as4_aggregator,
1262 struct in_addr *as4_aggregator_addr)
1263{
1264 int ignore_as4_path = 0;
1265 struct aspath *newpath;
1266 struct attr_extra *attre = attr->extra;
1267
Paul Jakmab881c702010-11-23 16:35:42 +00001268 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001269 {
1270 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1271 * if given.
1272 * It is worth a warning though, because the peer really
1273 * should not send them
1274 */
1275 if (BGP_DEBUG(as4, AS4))
1276 {
1277 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1278 zlog_debug ("[AS4] %s %s AS4_PATH",
1279 peer->host, "AS4 capable peer, yet it sent");
1280
1281 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1282 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1283 peer->host, "AS4 capable peer, yet it sent");
1284 }
1285
Paul Jakmab881c702010-11-23 16:35:42 +00001286 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001287 }
1288
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001289 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1290 * because that may override AS4_PATH
1291 */
1292 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1293 {
Paul Jakmab881c702010-11-23 16:35:42 +00001294 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001295 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001296 assert (attre);
1297
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001298 /* received both.
1299 * if the as_number in aggregator is not AS_TRANS,
1300 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1301 * and the Aggregator shall be taken as
1302 * info on the aggregating node, and the AS_PATH
1303 * shall be taken as the AS_PATH
1304 * otherwise
1305 * the Aggregator shall be ignored and the
1306 * AS4_AGGREGATOR shall be taken as the
1307 * Aggregating node and the AS_PATH is to be
1308 * constructed "as in all other cases"
1309 */
Paul Jakmab881c702010-11-23 16:35:42 +00001310 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001311 {
1312 /* ignore */
1313 if ( BGP_DEBUG(as4, AS4))
1314 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1315 " send AGGREGATOR != AS_TRANS and"
1316 " AS4_AGGREGATOR, so ignore"
1317 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1318 ignore_as4_path = 1;
1319 }
1320 else
1321 {
1322 /* "New_aggregator shall be taken as aggregator" */
1323 attre->aggregator_as = as4_aggregator;
1324 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1325 }
1326 }
1327 else
1328 {
1329 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1330 * That is bogus - but reading the conditions
1331 * we have to handle AS4_AGGREGATOR as if it were
1332 * AGGREGATOR in that case
1333 */
1334 if ( BGP_DEBUG(as4, AS4))
1335 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1336 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1337 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001338 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001339 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1340 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1341 }
1342 }
1343
1344 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001345 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001346 {
1347 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001348 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001349 attr->aspath = aspath_intern (newpath);
1350 }
Paul Jakmab881c702010-11-23 16:35:42 +00001351 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001352}
1353
paul718e3742002-12-13 20:15:29 +00001354/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001355static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001356bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001357{
Paul Jakma835315b2012-01-18 12:28:30 +00001358 struct peer *const peer = args->peer;
1359 struct attr *const attr = args->attr;
1360 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001361
paul718e3742002-12-13 20:15:29 +00001362 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001363 {
1364 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001365 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001366 }
Paul Jakma0c466382010-12-05 17:17:26 +00001367
1368 attr->community =
1369 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1370
1371 /* XXX: fix community_parse to use stream API and remove this */
1372 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001373
Paul Jakma0c466382010-12-05 17:17:26 +00001374 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001375 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001376 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001377 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001378
paul718e3742002-12-13 20:15:29 +00001379 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1380
Paul Jakmab881c702010-11-23 16:35:42 +00001381 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001382}
1383
1384/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001385static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001386bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001387{
Paul Jakma835315b2012-01-18 12:28:30 +00001388 struct peer *const peer = args->peer;
1389 struct attr *const attr = args->attr;
1390 const bgp_size_t length = args->length;
1391
Denis Ovsienkod595b562011-09-30 15:08:54 +04001392 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001393 if (length != 4)
1394 {
1395 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1396
Paul Jakma835315b2012-01-18 12:28:30 +00001397 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001398 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001399 args->total);
paul718e3742002-12-13 20:15:29 +00001400 }
1401
Paul Jakmafb982c22007-05-04 20:15:47 +00001402 (bgp_attr_extra_get (attr))->originator_id.s_addr
1403 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001404
1405 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1406
Paul Jakmab881c702010-11-23 16:35:42 +00001407 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001408}
1409
1410/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001411static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001412bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001413{
Paul Jakma835315b2012-01-18 12:28:30 +00001414 struct peer *const peer = args->peer;
1415 struct attr *const attr = args->attr;
1416 const bgp_size_t length = args->length;
1417
paul718e3742002-12-13 20:15:29 +00001418 /* Check length. */
1419 if (length % 4)
1420 {
1421 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1422
Paul Jakma835315b2012-01-18 12:28:30 +00001423 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1424 args->total);
paul718e3742002-12-13 20:15:29 +00001425 }
1426
Paul Jakmafb982c22007-05-04 20:15:47 +00001427 (bgp_attr_extra_get (attr))->cluster
1428 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001429
1430 /* XXX: Fix cluster_parse to use stream API and then remove this */
1431 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001432
1433 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1434
Paul Jakmab881c702010-11-23 16:35:42 +00001435 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001436}
1437
1438/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001439int
Paul Jakma835315b2012-01-18 12:28:30 +00001440bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1441 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001442{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001443 afi_t afi;
1444 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001445 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001446 size_t start;
paul718e3742002-12-13 20:15:29 +00001447 int ret;
1448 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001449 struct peer *const peer = args->peer;
1450 struct attr *const attr = args->attr;
1451 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001452 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001453
paul718e3742002-12-13 20:15:29 +00001454 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001455 s = BGP_INPUT(peer);
1456 start = stream_get_getp(s);
1457
1458 /* safe to read statically sized header? */
1459#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001460#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001461 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001462 {
1463 zlog_info ("%s: %s sent invalid length, %lu",
1464 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001465 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001466 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001467
paul718e3742002-12-13 20:15:29 +00001468 /* Load AFI, SAFI. */
1469 afi = stream_getw (s);
1470 safi = stream_getc (s);
1471
1472 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001473 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001474
Paul Jakma03292802008-06-07 20:37:10 +00001475 if (LEN_LEFT < attre->mp_nexthop_len)
1476 {
1477 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1478 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001479 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001480 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001481
paul718e3742002-12-13 20:15:29 +00001482 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001483 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001484 {
1485 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001486 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001487 /* Probably needed for RFC 2283 */
1488 if (attr->nexthop.s_addr == 0)
1489 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001490 break;
1491 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001492 stream_getl (s); /* RD high */
1493 stream_getl (s); /* RD low */
1494 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001495 break;
1496#ifdef HAVE_IPV6
1497 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001498 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001499 break;
1500 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001501 stream_get (&attre->mp_nexthop_global, s, 16);
1502 stream_get (&attre->mp_nexthop_local, s, 16);
1503 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001504 {
1505 char buf1[INET6_ADDRSTRLEN];
1506 char buf2[INET6_ADDRSTRLEN];
1507
1508 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001509 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 +00001510 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001511 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001512 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001513 buf2, INET6_ADDRSTRLEN));
1514
Paul Jakmafb982c22007-05-04 20:15:47 +00001515 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001516 }
1517 break;
1518#endif /* HAVE_IPV6 */
1519 default:
Paul Jakma03292802008-06-07 20:37:10 +00001520 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1521 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001522 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001523 }
1524
Paul Jakma03292802008-06-07 20:37:10 +00001525 if (!LEN_LEFT)
1526 {
1527 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1528 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001529 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001530 }
paul718e3742002-12-13 20:15:29 +00001531
Paul Jakma6e4ab122007-04-10 19:36:48 +00001532 {
1533 u_char val;
1534 if ((val = stream_getc (s)))
1535 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1536 peer->host, val);
1537 }
1538
1539 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001540 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001541 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001542 {
1543 zlog_info ("%s: (%s) Failed to read NLRI",
1544 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001545 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001546 }
paul718e3742002-12-13 20:15:29 +00001547
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001548 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001549 {
1550 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001551 if (ret < 0)
1552 {
1553 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
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 }
1558
1559 mp_update->afi = afi;
1560 mp_update->safi = safi;
1561 mp_update->nlri = stream_pnt (s);
1562 mp_update->length = nlri_len;
1563
paul9985f832005-02-09 15:51:56 +00001564 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001565
Paul Jakmab881c702010-11-23 16:35:42 +00001566 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001567#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001568}
1569
1570/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001571int
Paul Jakma835315b2012-01-18 12:28:30 +00001572bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001573 struct bgp_nlri *mp_withdraw)
1574{
1575 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001576 afi_t afi;
1577 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001578 u_int16_t withdraw_len;
1579 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001580 struct peer *const peer = args->peer;
1581 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001582
1583 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001584
1585#define BGP_MP_UNREACH_MIN_SIZE 3
1586 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001587 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001588
paul718e3742002-12-13 20:15:29 +00001589 afi = stream_getw (s);
1590 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001591
1592 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001593
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001594 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001595 {
1596 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1597 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001598 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001599 }
1600
1601 mp_withdraw->afi = afi;
1602 mp_withdraw->safi = safi;
1603 mp_withdraw->nlri = stream_pnt (s);
1604 mp_withdraw->length = withdraw_len;
1605
paul9985f832005-02-09 15:51:56 +00001606 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001607
Paul Jakmab881c702010-11-23 16:35:42 +00001608 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001609}
1610
1611/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001612static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001613bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001614{
Paul Jakma835315b2012-01-18 12:28:30 +00001615 struct peer *const peer = args->peer;
1616 struct attr *const attr = args->attr;
1617 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001618
paul718e3742002-12-13 20:15:29 +00001619 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001620 {
1621 if (attr->extra)
1622 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001623 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001624 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001625 }
Paul Jakma0c466382010-12-05 17:17:26 +00001626
1627 (bgp_attr_extra_get (attr))->ecommunity =
1628 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1629 /* XXX: fix ecommunity_parse to use stream API */
1630 stream_forward_getp (peer->ibuf, length);
1631
1632 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001633 return bgp_attr_malformed (args,
1634 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1635 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001636
paul718e3742002-12-13 20:15:29 +00001637 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1638
Paul Jakmab881c702010-11-23 16:35:42 +00001639 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001640}
1641
1642/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001643static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001644bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001645{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001646 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001647 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001648 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001649 struct peer *const peer = args->peer;
1650 struct attr *const attr = args->attr;
1651 u_char *const startp = args->startp;
1652 const u_char type = args->type;
1653 const u_char flag = args->flags;
1654 const bgp_size_t length = args->length;
1655
paul718e3742002-12-13 20:15:29 +00001656
hassof4184462005-02-01 20:13:16 +00001657 if (BGP_DEBUG (normal, NORMAL))
1658 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1659 peer->host, type, length);
1660
paul718e3742002-12-13 20:15:29 +00001661 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001662 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001663 "Unknown attribute type %d length %d is received", type, length);
1664
1665 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001666 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001667
paul718e3742002-12-13 20:15:29 +00001668 /* If any of the mandatory well-known attributes are not recognized,
1669 then the Error Subcode is set to Unrecognized Well-known
1670 Attribute. The Data field contains the unrecognized attribute
1671 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001672 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001673 {
Paul Jakma835315b2012-01-18 12:28:30 +00001674 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001675 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001676 args->total);
paul718e3742002-12-13 20:15:29 +00001677 }
1678
1679 /* Unrecognized non-transitive optional attributes must be quietly
1680 ignored and not passed along to other BGP peers. */
1681 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001682 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001683
1684 /* If a path with recognized transitive optional attribute is
1685 accepted and passed along to other BGP peers and the Partial bit
1686 in the Attribute Flags octet is set to 1 by some previous AS, it
1687 is not set back to 0 by the current AS. */
1688 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1689
1690 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001691 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001692 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001693
Paul Jakmafb982c22007-05-04 20:15:47 +00001694 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001695
1696 if (transit->val)
1697 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1698 transit->length + total);
1699 else
1700 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1701
1702 memcpy (transit->val + transit->length, startp, total);
1703 transit->length += total;
1704
Paul Jakmab881c702010-11-23 16:35:42 +00001705 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001706}
1707
1708/* Read attribute of update packet. This function is called from
1709 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001710bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001711bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1712 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1713{
1714 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001715 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001716 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001717 bgp_size_t length;
1718 u_char *startp, *endp;
1719 u_char *attr_endp;
1720 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001721 /* we need the as4_path only until we have synthesized the as_path with it */
1722 /* same goes for as4_aggregator */
1723 struct aspath *as4_path = NULL;
1724 as_t as4_aggregator = 0;
1725 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001726
1727 /* Initialize bitmap. */
1728 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1729
1730 /* End pointer of BGP attribute. */
1731 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001732
paul718e3742002-12-13 20:15:29 +00001733 /* Get attributes to the end of attribute length. */
1734 while (BGP_INPUT_PNT (peer) < endp)
1735 {
1736 /* Check remaining length check.*/
1737 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1738 {
gdtc29fdba2004-12-09 14:46:46 +00001739 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001740 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001741 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001742 peer->host,
1743 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001744
1745 bgp_notify_send (peer,
1746 BGP_NOTIFY_UPDATE_ERR,
1747 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001748 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001749 }
1750
1751 /* Fetch attribute flag and type. */
1752 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001753 /* "The lower-order four bits of the Attribute Flags octet are
1754 unused. They MUST be zero when sent and MUST be ignored when
1755 received." */
1756 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001757 type = stream_getc (BGP_INPUT (peer));
1758
Paul Jakma370b64a2007-12-22 16:49:52 +00001759 /* Check whether Extended-Length applies and is in bounds */
1760 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1761 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1762 {
1763 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001764 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001765 peer->host,
1766 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1767
1768 bgp_notify_send (peer,
1769 BGP_NOTIFY_UPDATE_ERR,
1770 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001771 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001772 }
Paul Jakma835315b2012-01-18 12:28:30 +00001773
paul718e3742002-12-13 20:15:29 +00001774 /* Check extended attribue length bit. */
1775 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1776 length = stream_getw (BGP_INPUT (peer));
1777 else
1778 length = stream_getc (BGP_INPUT (peer));
1779
1780 /* If any attribute appears more than once in the UPDATE
1781 message, then the Error Subcode is set to Malformed Attribute
1782 List. */
1783
1784 if (CHECK_BITMAP (seen, type))
1785 {
1786 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001787 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001788 peer->host, type);
1789
1790 bgp_notify_send (peer,
1791 BGP_NOTIFY_UPDATE_ERR,
1792 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001793 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001794 }
1795
1796 /* Set type to bitmap to check duplicate attribute. `type' is
1797 unsigned char so it never overflow bitmap range. */
1798
1799 SET_BITMAP (seen, type);
1800
1801 /* Overflow check. */
1802 attr_endp = BGP_INPUT_PNT (peer) + length;
1803
1804 if (attr_endp > endp)
1805 {
1806 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001807 "%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 +00001808 bgp_notify_send (peer,
1809 BGP_NOTIFY_UPDATE_ERR,
1810 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001811 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001812 }
Paul Jakma835315b2012-01-18 12:28:30 +00001813
1814 struct bgp_attr_parser_args attr_args = {
1815 .peer = peer,
1816 .length = length,
1817 .attr = attr,
1818 .type = type,
1819 .flags = flag,
1820 .startp = startp,
1821 .total = attr_endp - startp,
1822 };
1823
1824
1825 /* If any recognized attribute has Attribute Flags that conflict
1826 with the Attribute Type Code, then the Error Subcode is set to
1827 Attribute Flags Error. The Data field contains the erroneous
1828 attribute (type, length and value). */
1829 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001830 {
1831 bgp_attr_parse_ret_t ret;
1832 ret = bgp_attr_malformed (&attr_args,
1833 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1834 attr_args.total);
1835 if (ret == BGP_ATTR_PARSE_PROCEED)
1836 continue;
1837 return ret;
1838 }
paul718e3742002-12-13 20:15:29 +00001839
1840 /* OK check attribute and store it's value. */
1841 switch (type)
1842 {
1843 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001844 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001845 break;
1846 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001847 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001848 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001849 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001850 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001851 break;
paul718e3742002-12-13 20:15:29 +00001852 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001853 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001854 break;
1855 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001856 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001857 break;
1858 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001859 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001860 break;
1861 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001862 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001863 break;
1864 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001865 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001866 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001867 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001868 ret = bgp_attr_as4_aggregator (&attr_args,
1869 &as4_aggregator,
1870 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001871 break;
paul718e3742002-12-13 20:15:29 +00001872 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001873 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001874 break;
1875 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001876 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001877 break;
1878 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001879 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001880 break;
1881 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001882 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001883 break;
1884 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001885 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001886 break;
1887 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001888 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001889 break;
1890 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001891 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001892 break;
1893 }
Paul Jakmab881c702010-11-23 16:35:42 +00001894
1895 /* If hard error occured immediately return to the caller. */
1896 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001897 {
1898 zlog (peer->log, LOG_WARNING,
1899 "%s: Attribute %s, parse error",
1900 peer->host,
1901 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001902 bgp_notify_send (peer,
1903 BGP_NOTIFY_UPDATE_ERR,
1904 BGP_NOTIFY_UPDATE_MAL_ATTR);
1905 if (as4_path)
1906 aspath_unintern (&as4_path);
1907 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001908 }
Paul Jakmab881c702010-11-23 16:35:42 +00001909 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1910 {
1911
1912 zlog (peer->log, LOG_WARNING,
1913 "%s: Attribute %s, parse error - treating as withdrawal",
1914 peer->host,
1915 LOOKUP (attr_str, type));
1916 if (as4_path)
1917 aspath_unintern (&as4_path);
1918 return ret;
1919 }
1920
paul718e3742002-12-13 20:15:29 +00001921 /* Check the fetched length. */
1922 if (BGP_INPUT_PNT (peer) != attr_endp)
1923 {
1924 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001925 "%s: BGP attribute %s, fetch error",
1926 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001927 bgp_notify_send (peer,
1928 BGP_NOTIFY_UPDATE_ERR,
1929 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001930 if (as4_path)
1931 aspath_unintern (&as4_path);
1932 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001933 }
1934 }
1935
1936 /* Check final read pointer is same as end pointer. */
1937 if (BGP_INPUT_PNT (peer) != endp)
1938 {
1939 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001940 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001941 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001942 bgp_notify_send (peer,
1943 BGP_NOTIFY_UPDATE_ERR,
1944 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001945 if (as4_path)
1946 aspath_unintern (&as4_path);
1947 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001948 }
1949
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001950 /*
1951 * At this place we can see whether we got AS4_PATH and/or
1952 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1953 * We can not do this before we've read all attributes because
1954 * the as4 handling does not say whether AS4_PATH has to be sent
1955 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1956 * in relationship to AGGREGATOR.
1957 * So, to be defensive, we are not relying on any order and read
1958 * all attributes first, including these 32bit ones, and now,
1959 * afterwards, we look what and if something is to be done for as4.
1960 */
Paul Jakma835315b2012-01-18 12:28:30 +00001961 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001962 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001963 {
1964 if (as4_path)
1965 aspath_unintern (&as4_path);
1966 return BGP_ATTR_PARSE_ERROR;
1967 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001968
1969 /* At this stage, we have done all fiddling with as4, and the
1970 * resulting info is in attr->aggregator resp. attr->aspath
1971 * so we can chuck as4_aggregator and as4_path alltogether in
1972 * order to save memory
1973 */
Paul Jakmab881c702010-11-23 16:35:42 +00001974 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001975 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001976 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001977 /* The flag that we got this is still there, but that does not
1978 * do any trouble
1979 */
1980 }
1981 /*
1982 * The "rest" of the code does nothing with as4_aggregator.
1983 * there is no memory attached specifically which is not part
1984 * of the attr.
1985 * so ignoring just means do nothing.
1986 */
1987 /*
1988 * Finally do the checks on the aspath we did not do yet
1989 * because we waited for a potentially synthesized aspath.
1990 */
Paul Jakmab881c702010-11-23 16:35:42 +00001991 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001992 {
Paul Jakma835315b2012-01-18 12:28:30 +00001993 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001994 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001995 return ret;
1996 }
1997
paul718e3742002-12-13 20:15:29 +00001998 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001999 if (attr->extra && attr->extra->transit)
2000 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002001
Paul Jakmab881c702010-11-23 16:35:42 +00002002 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002003}
2004
2005/* Well-known attribute check. */
2006int
2007bgp_attr_check (struct peer *peer, struct attr *attr)
2008{
2009 u_char type = 0;
2010
2011 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2012 type = BGP_ATTR_ORIGIN;
2013
2014 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2015 type = BGP_ATTR_AS_PATH;
2016
2017 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2018 type = BGP_ATTR_NEXT_HOP;
2019
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002020 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002021 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2022 type = BGP_ATTR_LOCAL_PREF;
2023
2024 if (type)
2025 {
2026 zlog (peer->log, LOG_WARNING,
2027 "%s Missing well-known attribute %d.",
2028 peer->host, type);
2029 bgp_notify_send_with_data (peer,
2030 BGP_NOTIFY_UPDATE_ERR,
2031 BGP_NOTIFY_UPDATE_MISS_ATTR,
2032 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002033 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002034 }
Paul Jakmab881c702010-11-23 16:35:42 +00002035 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002036}
2037
2038int stream_put_prefix (struct stream *, struct prefix *);
2039
2040/* Make attribute packet. */
2041bgp_size_t
2042bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2043 struct stream *s, struct attr *attr, struct prefix *p,
2044 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002045 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002046{
paulfe69a502005-09-10 16:55:02 +00002047 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002048 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002049 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002050 int send_as4_path = 0;
2051 int send_as4_aggregator = 0;
2052 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002053
2054 if (! bgp)
2055 bgp = bgp_get_default ();
2056
2057 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002058 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002059
2060 /* Origin attribute. */
2061 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2062 stream_putc (s, BGP_ATTR_ORIGIN);
2063 stream_putc (s, 1);
2064 stream_putc (s, attr->origin);
2065
2066 /* AS path attribute. */
2067
2068 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002069 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002070 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002071 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002072 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002073 {
2074 aspath = aspath_dup (attr->aspath);
2075
2076 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2077 {
2078 /* Strip the confed info, and then stuff our path CONFED_ID
2079 on the front */
2080 aspath = aspath_delete_confed_seq (aspath);
2081 aspath = aspath_add_seq (aspath, bgp->confed_id);
2082 }
2083 else
2084 {
2085 aspath = aspath_add_seq (aspath, peer->local_as);
2086 if (peer->change_local_as)
2087 aspath = aspath_add_seq (aspath, peer->change_local_as);
2088 }
2089 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002090 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002091 {
2092 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2093 aspath = aspath_dup (attr->aspath);
2094 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2095 }
2096 else
2097 aspath = attr->aspath;
2098
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002099 /* If peer is not AS4 capable, then:
2100 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2101 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2102 * types are in it (i.e. exclude them if they are there)
2103 * AND do this only if there is at least one asnum > 65535 in the path!
2104 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2105 * all ASnums > 65535 to BGP_AS_TRANS
2106 */
paul718e3742002-12-13 20:15:29 +00002107
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002108 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2109 stream_putc (s, BGP_ATTR_AS_PATH);
2110 aspath_sizep = stream_get_endp (s);
2111 stream_putw (s, 0);
2112 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2113
2114 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2115 * in the path
2116 */
2117 if (!use32bit && aspath_has_as4 (aspath))
2118 send_as4_path = 1; /* we'll do this later, at the correct place */
2119
paul718e3742002-12-13 20:15:29 +00002120 /* Nexthop attribute. */
2121 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2122 {
2123 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2124 stream_putc (s, BGP_ATTR_NEXT_HOP);
2125 stream_putc (s, 4);
2126 if (safi == SAFI_MPLS_VPN)
2127 {
2128 if (attr->nexthop.s_addr == 0)
2129 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2130 else
2131 stream_put_ipv4 (s, attr->nexthop.s_addr);
2132 }
2133 else
2134 stream_put_ipv4 (s, attr->nexthop.s_addr);
2135 }
2136
2137 /* MED attribute. */
2138 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2139 {
2140 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2141 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2142 stream_putc (s, 4);
2143 stream_putl (s, attr->med);
2144 }
2145
2146 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002147 if (peer->sort == BGP_PEER_IBGP ||
2148 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002149 {
2150 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2151 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2152 stream_putc (s, 4);
2153 stream_putl (s, attr->local_pref);
2154 }
2155
2156 /* Atomic aggregate. */
2157 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2158 {
2159 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2160 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2161 stream_putc (s, 0);
2162 }
2163
2164 /* Aggregator. */
2165 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2166 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002167 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002168
2169 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002170 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2171 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002172
2173 if (use32bit)
2174 {
2175 /* AS4 capable peer */
2176 stream_putc (s, 8);
2177 stream_putl (s, attr->extra->aggregator_as);
2178 }
2179 else
2180 {
2181 /* 2-byte AS peer */
2182 stream_putc (s, 6);
2183
2184 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2185 if ( attr->extra->aggregator_as > 65535 )
2186 {
2187 stream_putw (s, BGP_AS_TRANS);
2188
2189 /* we have to send AS4_AGGREGATOR, too.
2190 * we'll do that later in order to send attributes in ascending
2191 * order.
2192 */
2193 send_as4_aggregator = 1;
2194 }
2195 else
2196 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2197 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002198 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002199 }
2200
2201 /* Community attribute. */
2202 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2203 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2204 {
2205 if (attr->community->size * 4 > 255)
2206 {
2207 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2208 stream_putc (s, BGP_ATTR_COMMUNITIES);
2209 stream_putw (s, attr->community->size * 4);
2210 }
2211 else
2212 {
2213 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2214 stream_putc (s, BGP_ATTR_COMMUNITIES);
2215 stream_putc (s, attr->community->size * 4);
2216 }
2217 stream_put (s, attr->community->val, attr->community->size * 4);
2218 }
2219
2220 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002221 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002222 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002223 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002224 {
2225 /* Originator ID. */
2226 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2227 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2228 stream_putc (s, 4);
2229
2230 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002231 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002232 else
2233 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002234
2235 /* Cluster list. */
2236 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2237 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2238
Paul Jakma9eda90c2007-08-30 13:36:17 +00002239 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002240 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002241 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002242 /* If this peer configuration's parent BGP has cluster_id. */
2243 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2244 stream_put_in_addr (s, &bgp->cluster_id);
2245 else
2246 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002247 stream_put (s, attr->extra->cluster->list,
2248 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002249 }
2250 else
2251 {
2252 stream_putc (s, 4);
2253 /* If this peer configuration's parent BGP has cluster_id. */
2254 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2255 stream_put_in_addr (s, &bgp->cluster_id);
2256 else
2257 stream_put_in_addr (s, &bgp->router_id);
2258 }
2259 }
2260
2261#ifdef HAVE_IPV6
2262 /* If p is IPv6 address put it into attribute. */
2263 if (p->family == AF_INET6)
2264 {
2265 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002266 struct attr_extra *attre = attr->extra;
2267
2268 assert (attr->extra);
2269
paul718e3742002-12-13 20:15:29 +00002270 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2271 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002272 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002273 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002274 stream_putw (s, AFI_IP6); /* AFI */
2275 stream_putc (s, safi); /* SAFI */
2276
Paul Jakmafb982c22007-05-04 20:15:47 +00002277 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002278
Paul Jakmafb982c22007-05-04 20:15:47 +00002279 if (attre->mp_nexthop_len == 16)
2280 stream_put (s, &attre->mp_nexthop_global, 16);
2281 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002282 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002283 stream_put (s, &attre->mp_nexthop_global, 16);
2284 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002285 }
2286
2287 /* SNPA */
2288 stream_putc (s, 0);
2289
paul718e3742002-12-13 20:15:29 +00002290 /* Prefix write. */
2291 stream_put_prefix (s, p);
2292
2293 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002294 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002295 }
2296#endif /* HAVE_IPV6 */
2297
2298 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2299 {
2300 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002301
2302 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2303 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002304 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002305 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002306 stream_putw (s, AFI_IP); /* AFI */
2307 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2308
2309 stream_putc (s, 4);
2310 stream_put_ipv4 (s, attr->nexthop.s_addr);
2311
2312 /* SNPA */
2313 stream_putc (s, 0);
2314
paul718e3742002-12-13 20:15:29 +00002315 /* Prefix write. */
2316 stream_put_prefix (s, p);
2317
2318 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002319 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002320 }
2321
2322 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2323 {
2324 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002325
2326 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2327 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002328 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002329 stream_putc (s, 0); /* Length of this attribute. */
2330 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002331 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002332
2333 stream_putc (s, 12);
2334 stream_putl (s, 0);
2335 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002336 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002337
2338 /* SNPA */
2339 stream_putc (s, 0);
2340
paul718e3742002-12-13 20:15:29 +00002341 /* Tag, RD, Prefix write. */
2342 stream_putc (s, p->prefixlen + 88);
2343 stream_put (s, tag, 3);
2344 stream_put (s, prd->val, 8);
2345 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2346
2347 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002348 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002349 }
2350
2351 /* Extended Communities attribute. */
2352 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2353 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2354 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002355 struct attr_extra *attre = attr->extra;
2356
2357 assert (attre);
2358
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002359 if (peer->sort == BGP_PEER_IBGP
2360 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002361 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002362 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002363 {
2364 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2365 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002366 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002367 }
2368 else
2369 {
2370 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2371 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002372 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002373 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002374 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002375 }
2376 else
2377 {
paul5228ad22004-06-04 17:58:18 +00002378 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002379 int tbit;
2380 int ecom_tr_size = 0;
2381 int i;
2382
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002384 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002385 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002386 tbit = *pnt;
2387
2388 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2389 continue;
2390
2391 ecom_tr_size++;
2392 }
2393
2394 if (ecom_tr_size)
2395 {
2396 if (ecom_tr_size * 8 > 255)
2397 {
2398 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2399 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2400 stream_putw (s, ecom_tr_size * 8);
2401 }
2402 else
2403 {
2404 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2405 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2406 stream_putc (s, ecom_tr_size * 8);
2407 }
2408
Paul Jakmafb982c22007-05-04 20:15:47 +00002409 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002410 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002412 tbit = *pnt;
2413
2414 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2415 continue;
2416
2417 stream_put (s, pnt, 8);
2418 }
2419 }
paul718e3742002-12-13 20:15:29 +00002420 }
paul718e3742002-12-13 20:15:29 +00002421 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002422
2423 if ( send_as4_path )
2424 {
2425 /* If the peer is NOT As4 capable, AND */
2426 /* there are ASnums > 65535 in path THEN
2427 * give out AS4_PATH */
2428
2429 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2430 * path segments!
2431 * Hm, I wonder... confederation things *should* only be at
2432 * the beginning of an aspath, right? Then we should use
2433 * aspath_delete_confed_seq for this, because it is already
2434 * there! (JK)
2435 * Folks, talk to me: what is reasonable here!?
2436 */
2437 aspath = aspath_delete_confed_seq (aspath);
2438
2439 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2440 stream_putc (s, BGP_ATTR_AS4_PATH);
2441 aspath_sizep = stream_get_endp (s);
2442 stream_putw (s, 0);
2443 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2444 }
2445
2446 if (aspath != attr->aspath)
2447 aspath_free (aspath);
2448
2449 if ( send_as4_aggregator )
2450 {
2451 assert (attr->extra);
2452
2453 /* send AS4_AGGREGATOR, at this place */
2454 /* this section of code moved here in order to ensure the correct
2455 * *ascending* order of attributes
2456 */
2457 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2458 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2459 stream_putc (s, 8);
2460 stream_putl (s, attr->extra->aggregator_as);
2461 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2462 }
Paul Jakma41367172007-08-06 15:24:51 +00002463
paul718e3742002-12-13 20:15:29 +00002464 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002465 if (attr->extra && attr->extra->transit)
2466 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002467
2468 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002469 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002470}
2471
2472bgp_size_t
2473bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2474 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002475 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002476{
2477 unsigned long cp;
2478 unsigned long attrlen_pnt;
2479 bgp_size_t size;
2480
paul9985f832005-02-09 15:51:56 +00002481 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002482
2483 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2484 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2485
paul9985f832005-02-09 15:51:56 +00002486 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002487 stream_putc (s, 0); /* Length of this attribute. */
2488
2489 stream_putw (s, family2afi (p->family));
2490
2491 if (safi == SAFI_MPLS_VPN)
2492 {
2493 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002494 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002495
2496 /* prefix. */
2497 stream_putc (s, p->prefixlen + 88);
2498 stream_put (s, tag, 3);
2499 stream_put (s, prd->val, 8);
2500 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2501 }
2502 else
2503 {
2504 /* SAFI */
2505 stream_putc (s, safi);
2506
2507 /* prefix */
2508 stream_put_prefix (s, p);
2509 }
2510
2511 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002512 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002513 stream_putc_at (s, attrlen_pnt, size);
2514
paul9985f832005-02-09 15:51:56 +00002515 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002516}
2517
2518/* Initialization of attribute. */
2519void
paulfe69a502005-09-10 16:55:02 +00002520bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002521{
paul718e3742002-12-13 20:15:29 +00002522 aspath_init ();
2523 attrhash_init ();
2524 community_init ();
2525 ecommunity_init ();
2526 cluster_init ();
2527 transit_init ();
2528}
2529
Chris Caputo228da422009-07-18 05:44:03 +00002530void
2531bgp_attr_finish (void)
2532{
2533 aspath_finish ();
2534 attrhash_finish ();
2535 community_finish ();
2536 ecommunity_finish ();
2537 cluster_finish ();
2538 transit_finish ();
2539}
2540
paul718e3742002-12-13 20:15:29 +00002541/* Make attribute packet. */
2542void
paula3845922003-10-18 01:30:50 +00002543bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2544 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002545{
2546 unsigned long cp;
2547 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002548 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002549 struct aspath *aspath;
2550
2551 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002552 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002553
2554 /* Place holder of length. */
2555 stream_putw (s, 0);
2556
2557 /* Origin attribute. */
2558 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2559 stream_putc (s, BGP_ATTR_ORIGIN);
2560 stream_putc (s, 1);
2561 stream_putc (s, attr->origin);
2562
2563 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002564
2565 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2566 stream_putc (s, BGP_ATTR_AS_PATH);
2567 aspath_lenp = stream_get_endp (s);
2568 stream_putw (s, 0);
2569
2570 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002571
2572 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002573 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2574 if(prefix != NULL
2575#ifdef HAVE_IPV6
2576 && prefix->family != AF_INET6
2577#endif /* HAVE_IPV6 */
2578 )
2579 {
2580 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2581 stream_putc (s, BGP_ATTR_NEXT_HOP);
2582 stream_putc (s, 4);
2583 stream_put_ipv4 (s, attr->nexthop.s_addr);
2584 }
paul718e3742002-12-13 20:15:29 +00002585
2586 /* MED attribute. */
2587 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2588 {
2589 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2590 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2591 stream_putc (s, 4);
2592 stream_putl (s, attr->med);
2593 }
2594
2595 /* Local preference. */
2596 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2597 {
2598 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2599 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2600 stream_putc (s, 4);
2601 stream_putl (s, attr->local_pref);
2602 }
2603
2604 /* Atomic aggregate. */
2605 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2606 {
2607 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2608 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2609 stream_putc (s, 0);
2610 }
2611
2612 /* Aggregator. */
2613 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2614 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002615 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002616 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2617 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002618 stream_putc (s, 8);
2619 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002620 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002621 }
2622
2623 /* Community attribute. */
2624 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2625 {
2626 if (attr->community->size * 4 > 255)
2627 {
2628 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2629 stream_putc (s, BGP_ATTR_COMMUNITIES);
2630 stream_putw (s, attr->community->size * 4);
2631 }
2632 else
2633 {
2634 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2635 stream_putc (s, BGP_ATTR_COMMUNITIES);
2636 stream_putc (s, attr->community->size * 4);
2637 }
2638 stream_put (s, attr->community->val, attr->community->size * 4);
2639 }
2640
paula3845922003-10-18 01:30:50 +00002641#ifdef HAVE_IPV6
2642 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002643 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2644 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002645 {
2646 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002647 struct attr_extra *attre = attr->extra;
2648
paula3845922003-10-18 01:30:50 +00002649 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2650 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002651 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002652
2653 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002654 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002655 stream_putw(s, AFI_IP6); /* AFI */
2656 stream_putc(s, SAFI_UNICAST); /* SAFI */
2657
2658 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002659 stream_putc(s, attre->mp_nexthop_len);
2660 stream_put(s, &attre->mp_nexthop_global, 16);
2661 if (attre->mp_nexthop_len == 32)
2662 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002663
2664 /* SNPA */
2665 stream_putc(s, 0);
2666
2667 /* Prefix */
2668 stream_put_prefix(s, prefix);
2669
2670 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002671 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002672 }
2673#endif /* HAVE_IPV6 */
2674
paul718e3742002-12-13 20:15:29 +00002675 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002676 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002677 stream_putw_at (s, cp, len);
2678}