blob: bb21fe19dd525312645498b2ae8e3ed1bbe7460e [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
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000655bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000656{
657 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000658 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000659
paul718e3742002-12-13 20:15:29 +0000660 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000662
663 tmp = *(*attr);
664
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000665 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000666 {
Paul Jakmab881c702010-11-23 16:35:42 +0000667 tmp.extra = bgp_attr_extra_new ();
668 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000669 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000670
paul718e3742002-12-13 20:15:29 +0000671 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000673 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000674 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000675 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000676 bgp_attr_extra_free (*attr);
677 XFREE (MTYPE_ATTR, *attr);
678 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000679 }
680
Paul Jakmab881c702010-11-23 16:35:42 +0000681 bgp_attr_unintern_sub (&tmp);
Oleg A. Arkhangelskyce0af6f2011-12-03 15:18:19 +0400682 bgp_attr_extra_free (&tmp);
paul718e3742002-12-13 20:15:29 +0000683}
684
685void
686bgp_attr_flush (struct attr *attr)
687{
688 if (attr->aspath && ! attr->aspath->refcnt)
689 aspath_free (attr->aspath);
690 if (attr->community && ! attr->community->refcnt)
691 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000692 if (attr->extra)
693 {
694 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000695
Paul Jakmafb982c22007-05-04 20:15:47 +0000696 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000697 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000698 if (attre->cluster && ! attre->cluster->refcnt)
699 cluster_free (attre->cluster);
700 if (attre->transit && ! attre->transit->refcnt)
701 transit_free (attre->transit);
702 }
paul718e3742002-12-13 20:15:29 +0000703}
704
Paul Jakmab881c702010-11-23 16:35:42 +0000705/* Implement draft-scudder-idr-optional-transitive behaviour and
706 * avoid resetting sessions for malformed attributes which are
707 * are partial/optional and hence where the error likely was not
708 * introduced by the sending neighbour.
709 */
710static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000711bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
712 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000713{
Paul Jakma835315b2012-01-18 12:28:30 +0000714 struct peer *const peer = args->peer;
715 const u_int8_t flags = args->flags;
716 /* startp and length must be special-cased, as whether or not to
717 * send the attribute data with the NOTIFY depends on the error,
718 * the caller therefore signals this with the seperate length argument
719 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000720 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000721
Paul Jakmab881c702010-11-23 16:35:42 +0000722 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000723 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000724 {
725 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000726 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000727 return BGP_ATTR_PARSE_ERROR;
728
729 }
730
Paul Jakmabd471fe2012-03-15 11:30:00 +0000731 /* Adjust the stream getp to the end of the attribute, in case we can
732 * still proceed but the caller hasn't read all the attribute.
733 */
734 stream_set_getp (BGP_INPUT (peer),
735 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
736 + args->total);
737
Paul Jakma835315b2012-01-18 12:28:30 +0000738 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100739 /* where an attribute is relatively inconsequential, e.g. it does not
740 * affect route selection, and can be safely ignored, then any such
741 * attributes which are malformed should just be ignored and the route
742 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000743 */
744 case BGP_ATTR_AS4_AGGREGATOR:
745 case BGP_ATTR_AGGREGATOR:
746 case BGP_ATTR_ATOMIC_AGGREGATE:
747 return BGP_ATTR_PARSE_PROCEED;
748
749 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100750 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000751 */
752 case BGP_ATTR_ORIGIN:
753 case BGP_ATTR_AS_PATH:
754 case BGP_ATTR_NEXT_HOP:
755 case BGP_ATTR_MULTI_EXIT_DISC:
756 case BGP_ATTR_LOCAL_PREF:
757 case BGP_ATTR_COMMUNITIES:
758 case BGP_ATTR_ORIGINATOR_ID:
759 case BGP_ATTR_CLUSTER_LIST:
760 case BGP_ATTR_MP_REACH_NLRI:
761 case BGP_ATTR_MP_UNREACH_NLRI:
762 case BGP_ATTR_EXT_COMMUNITIES:
763 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000764 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000765 return BGP_ATTR_PARSE_ERROR;
766 }
767
768 /* Partial optional attributes that are malformed should not cause
769 * the whole session to be reset. Instead treat it as a withdrawal
770 * of the routes, if possible.
771 */
Paul Jakma835315b2012-01-18 12:28:30 +0000772 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
773 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
774 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000775 return BGP_ATTR_PARSE_WITHDRAW;
776
777 /* default to reset */
778 return BGP_ATTR_PARSE_ERROR;
779}
780
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400781/* Find out what is wrong with the path attribute flag bits and log the error.
782 "Flag bits" here stand for Optional, Transitive and Partial, but not for
783 Extended Length. Checking O/T/P bits at once implies, that the attribute
784 being diagnosed is defined by RFC as either a "well-known" or an "optional,
785 non-transitive" attribute. */
786static void
Paul Jakma835315b2012-01-18 12:28:30 +0000787bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
788 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400789)
790{
791 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000792 u_char real_flags = args->flags;
793 const u_int8_t attr_code = args->type;
794
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400795 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
796 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
797 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
798 if
799 (
800 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
801 CHECK_FLAG (real_flags, attr_flag_str[i].key)
802 )
803 {
Paul Jakma835315b2012-01-18 12:28:30 +0000804 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400805 LOOKUP (attr_str, attr_code),
806 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
807 attr_flag_str[i].str);
808 seen = 1;
809 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100810 if (!seen)
811 {
812 zlog (args->peer->log, LOG_DEBUG,
813 "Strange, %s called for attr %s, but no problem found with flags"
814 " (real flags 0x%x, desired 0x%x)",
815 __func__, LOOKUP (attr_str, attr_code),
816 real_flags, desired_flags);
817 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400818}
819
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000820/* Required flags for attributes. EXTLEN will be masked off when testing,
821 * as will PARTIAL for optional+transitive attributes.
822 */
823const u_int8_t attr_flags_values [] = {
824 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
825 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
826 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
827 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
828 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
829 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
830 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
831 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
832 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
833 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
834 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
835 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
836 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
837 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
838 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
839};
840static const size_t attr_flags_values_max =
841 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
842
843static int
Paul Jakma835315b2012-01-18 12:28:30 +0000844bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000845{
846 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000847 const u_int8_t flags = args->flags;
848 const u_int8_t attr_code = args->type;
849 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000850
851 /* there may be attributes we don't know about */
852 if (attr_code > attr_flags_values_max)
853 return 0;
854 if (attr_flags_values[attr_code] == 0)
855 return 0;
856
857 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
858 * 1."
859 */
860 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
861 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
862 {
863 zlog (peer->log, LOG_ERR,
864 "%s well-known attributes must have transitive flag set (%x)",
865 LOOKUP (attr_str, attr_code), flags);
866 return 1;
867 }
868
869 /* "For well-known attributes and for optional non-transitive attributes,
870 * the Partial bit MUST be set to 0."
871 */
872 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
873 {
874 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
875 {
876 zlog (peer->log, LOG_ERR,
877 "%s well-known attribute "
878 "must NOT have the partial flag set (%x)",
879 LOOKUP (attr_str, attr_code), flags);
880 return 1;
881 }
882 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
883 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
884 {
885 zlog (peer->log, LOG_ERR,
886 "%s optional + transitive attribute "
887 "must NOT have the partial flag set (%x)",
888 LOOKUP (attr_str, attr_code), flags);
889 return 1;
890 }
891 }
892
893 /* Optional transitive attributes may go through speakers that don't
894 * reocgnise them and set the Partial bit.
895 */
896 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
897 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
898 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
899
Paul Jakma683f2b82012-03-23 14:58:45 +0000900 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000901 == attr_flags_values[attr_code])
902 return 0;
903
Paul Jakma835315b2012-01-18 12:28:30 +0000904 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000905 return 1;
906}
907
paul718e3742002-12-13 20:15:29 +0000908/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000909static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000910bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000911{
Paul Jakma835315b2012-01-18 12:28:30 +0000912 struct peer *const peer = args->peer;
913 struct attr *const attr = args->attr;
914 const bgp_size_t length = args->length;
915
paul718e3742002-12-13 20:15:29 +0000916 /* If any recognized attribute has Attribute Length that conflicts
917 with the expected length (based on the attribute type code), then
918 the Error Subcode is set to Attribute Length Error. The Data
919 field contains the erroneous attribute (type, length and
920 value). */
921 if (length != 1)
922 {
923 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
924 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000925 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000926 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000927 args->total);
paul718e3742002-12-13 20:15:29 +0000928 }
929
930 /* Fetch origin attribute. */
931 attr->origin = stream_getc (BGP_INPUT (peer));
932
933 /* If the ORIGIN attribute has an undefined value, then the Error
934 Subcode is set to Invalid Origin Attribute. The Data field
935 contains the unrecognized attribute (type, length and value). */
936 if ((attr->origin != BGP_ORIGIN_IGP)
937 && (attr->origin != BGP_ORIGIN_EGP)
938 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
939 {
940 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
941 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000942 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000943 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000944 args->total);
paul718e3742002-12-13 20:15:29 +0000945 }
946
947 /* Set oring attribute flag. */
948 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
949
950 return 0;
951}
Paul Jakmaab005292010-11-27 22:48:34 +0000952
953/* Parse AS path information. This function is wrapper of
954 aspath_parse. */
955static int
Paul Jakma835315b2012-01-18 12:28:30 +0000956bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000957{
Paul Jakma835315b2012-01-18 12:28:30 +0000958 struct attr *const attr = args->attr;
959 struct peer *const peer = args->peer;
960 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000961
Paul Jakmaab005292010-11-27 22:48:34 +0000962 /*
963 * peer with AS4 => will get 4Byte ASnums
964 * otherwise, will get 16 Bit
965 */
966 attr->aspath = aspath_parse (peer->ibuf, length,
967 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
968
969 /* In case of IBGP, length will be zero. */
970 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000971 {
Paul Jakmab881c702010-11-23 16:35:42 +0000972 zlog (peer->log, LOG_ERR,
973 "Malformed AS path from %s, length is %d",
974 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000975 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000976 }
Chris Hallcddb8112010-08-09 22:31:37 +0400977
Paul Jakmaab005292010-11-27 22:48:34 +0000978 /* Set aspath attribute flag. */
979 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000980
Paul Jakmab881c702010-11-23 16:35:42 +0000981 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000982}
983
Paul Jakmab881c702010-11-23 16:35:42 +0000984static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000985bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000986{
987 /* These checks were part of bgp_attr_aspath, but with
988 * as4 we should to check aspath things when
989 * aspath synthesizing with as4_path has already taken place.
990 * Otherwise we check ASPATH and use the synthesized thing, and that is
991 * not right.
992 * So do the checks later, i.e. here
993 */
994 struct bgp *bgp = peer->bgp;
995 struct aspath *aspath;
996
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300997 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000998 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
999 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001000 {
1001 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001002 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1003 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1004 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001005 }
1006
paul718e3742002-12-13 20:15:29 +00001007 /* First AS check for EBGP. */
1008 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1009 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001010 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001011 && ! aspath_firstas_check (attr->aspath, peer->as))
1012 {
1013 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001014 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001015 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1016 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1017 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001018 }
1019 }
1020
1021 /* local-as prepend */
1022 if (peer->change_local_as &&
1023 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1024 {
1025 aspath = aspath_dup (attr->aspath);
1026 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001027 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001028 attr->aspath = aspath_intern (aspath);
1029 }
1030
Paul Jakmab881c702010-11-23 16:35:42 +00001031 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001032}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001033
Paul Jakmaab005292010-11-27 22:48:34 +00001034/* Parse AS4 path information. This function is another wrapper of
1035 aspath_parse. */
1036static int
Paul Jakma835315b2012-01-18 12:28:30 +00001037bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001038{
Paul Jakma835315b2012-01-18 12:28:30 +00001039 struct peer *const peer = args->peer;
1040 struct attr *const attr = args->attr;
1041 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001042
Paul Jakmaab005292010-11-27 22:48:34 +00001043 *as4_path = aspath_parse (peer->ibuf, length, 1);
1044
Paul Jakmab881c702010-11-23 16:35:42 +00001045 /* In case of IBGP, length will be zero. */
1046 if (!*as4_path)
1047 {
1048 zlog (peer->log, LOG_ERR,
1049 "Malformed AS4 path from %s, length is %d",
1050 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001051 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001052 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001053 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001054 }
1055
Paul Jakmaab005292010-11-27 22:48:34 +00001056 /* Set aspath attribute flag. */
1057 if (as4_path)
1058 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1059
Paul Jakmab881c702010-11-23 16:35:42 +00001060 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001061}
1062
paul718e3742002-12-13 20:15:29 +00001063/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001064static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001065bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001066{
Paul Jakma835315b2012-01-18 12:28:30 +00001067 struct peer *const peer = args->peer;
1068 struct attr *const attr = args->attr;
1069 const bgp_size_t length = args->length;
1070
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001071 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001072
paul718e3742002-12-13 20:15:29 +00001073 /* Check nexthop attribute length. */
1074 if (length != 4)
1075 {
1076 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1077 length);
1078
Paul Jakma835315b2012-01-18 12:28:30 +00001079 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001080 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001081 args->total);
paul718e3742002-12-13 20:15:29 +00001082 }
1083
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001084 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1085 attribute must result in a NOTIFICATION message (this is implemented below).
1086 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1087 logged locally (this is implemented somewhere else). The UPDATE message
1088 gets ignored in any of these cases. */
1089 nexthop_n = stream_get_ipv4 (peer->ibuf);
1090 nexthop_h = ntohl (nexthop_n);
1091 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1092 {
1093 char buf[INET_ADDRSTRLEN];
1094 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1095 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001096 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001097 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001098 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001099 }
1100
1101 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001102 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1103
Paul Jakmab881c702010-11-23 16:35:42 +00001104 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001105}
1106
1107/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001108static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001109bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001110{
Paul Jakma835315b2012-01-18 12:28:30 +00001111 struct peer *const peer = args->peer;
1112 struct attr *const attr = args->attr;
1113 const bgp_size_t length = args->length;
1114
paul718e3742002-12-13 20:15:29 +00001115 /* Length check. */
1116 if (length != 4)
1117 {
1118 zlog (peer->log, LOG_ERR,
1119 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001120
Paul Jakma835315b2012-01-18 12:28:30 +00001121 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001122 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001123 args->total);
paul718e3742002-12-13 20:15:29 +00001124 }
1125
1126 attr->med = stream_getl (peer->ibuf);
1127
1128 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1129
Paul Jakmab881c702010-11-23 16:35:42 +00001130 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001131}
1132
1133/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001134static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001135bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001136{
Paul Jakma835315b2012-01-18 12:28:30 +00001137 struct peer *const peer = args->peer;
1138 struct attr *const attr = args->attr;
1139 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001140
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001141 /* Length check. */
1142 if (length != 4)
1143 {
Paul Jakma835315b2012-01-18 12:28:30 +00001144 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1145 length);
1146 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001147 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001148 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001149 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001150
paul718e3742002-12-13 20:15:29 +00001151 /* If it is contained in an UPDATE message that is received from an
1152 external peer, then this attribute MUST be ignored by the
1153 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001154 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001155 {
paul9985f832005-02-09 15:51:56 +00001156 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001157 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001158 }
1159
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001160 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001161
1162 /* Set atomic aggregate flag. */
1163 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1164
Paul Jakmab881c702010-11-23 16:35:42 +00001165 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001166}
1167
1168/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001169static int
Paul Jakma835315b2012-01-18 12:28:30 +00001170bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001171{
Paul Jakma835315b2012-01-18 12:28:30 +00001172 struct peer *const peer = args->peer;
1173 struct attr *const attr = args->attr;
1174 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001175
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001176 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001177 if (length != 0)
1178 {
Paul Jakma835315b2012-01-18 12:28:30 +00001179 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1180 length);
1181 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001182 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001183 args->total);
paul718e3742002-12-13 20:15:29 +00001184 }
1185
1186 /* Set atomic aggregate flag. */
1187 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1188
Paul Jakmab881c702010-11-23 16:35:42 +00001189 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001190}
1191
1192/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001193static int
Paul Jakma835315b2012-01-18 12:28:30 +00001194bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001195{
Paul Jakma835315b2012-01-18 12:28:30 +00001196 struct peer *const peer = args->peer;
1197 struct attr *const attr = args->attr;
1198 const bgp_size_t length = args->length;
1199
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001200 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001201 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001202
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001203 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001204 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205 wantedlen = 8;
1206
1207 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001208 {
Paul Jakma835315b2012-01-18 12:28:30 +00001209 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1210 wantedlen, length);
1211 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001212 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001213 args->total);
paul718e3742002-12-13 20:15:29 +00001214 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001215
1216 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1217 attre->aggregator_as = stream_getl (peer->ibuf);
1218 else
1219 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001220 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001221
1222 /* Set atomic aggregate flag. */
1223 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1224
Paul Jakmab881c702010-11-23 16:35:42 +00001225 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001226}
1227
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001228/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001229static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001230bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1231 as_t *as4_aggregator_as,
1232 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001233{
Paul Jakma835315b2012-01-18 12:28:30 +00001234 struct peer *const peer = args->peer;
1235 struct attr *const attr = args->attr;
1236 const bgp_size_t length = args->length;
1237
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001238 if (length != 8)
1239 {
Paul Jakma835315b2012-01-18 12:28:30 +00001240 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1241 length);
1242 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001243 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001244 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001245 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001246
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001247 *as4_aggregator_as = stream_getl (peer->ibuf);
1248 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1249
1250 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1251
Paul Jakmab881c702010-11-23 16:35:42 +00001252 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001253}
1254
1255/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1256 */
Paul Jakmab881c702010-11-23 16:35:42 +00001257static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001258bgp_attr_munge_as4_attrs (struct peer *const peer,
1259 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001260 struct aspath *as4_path, as_t as4_aggregator,
1261 struct in_addr *as4_aggregator_addr)
1262{
1263 int ignore_as4_path = 0;
1264 struct aspath *newpath;
1265 struct attr_extra *attre = attr->extra;
1266
Paul Jakmab881c702010-11-23 16:35:42 +00001267 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001268 {
1269 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1270 * if given.
1271 * It is worth a warning though, because the peer really
1272 * should not send them
1273 */
1274 if (BGP_DEBUG(as4, AS4))
1275 {
1276 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1277 zlog_debug ("[AS4] %s %s AS4_PATH",
1278 peer->host, "AS4 capable peer, yet it sent");
1279
1280 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1281 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1282 peer->host, "AS4 capable peer, yet it sent");
1283 }
1284
Paul Jakmab881c702010-11-23 16:35:42 +00001285 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001286 }
1287
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001288 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1289 * because that may override AS4_PATH
1290 */
1291 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1292 {
Paul Jakmab881c702010-11-23 16:35:42 +00001293 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001294 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001295 assert (attre);
1296
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001297 /* received both.
1298 * if the as_number in aggregator is not AS_TRANS,
1299 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1300 * and the Aggregator shall be taken as
1301 * info on the aggregating node, and the AS_PATH
1302 * shall be taken as the AS_PATH
1303 * otherwise
1304 * the Aggregator shall be ignored and the
1305 * AS4_AGGREGATOR shall be taken as the
1306 * Aggregating node and the AS_PATH is to be
1307 * constructed "as in all other cases"
1308 */
Paul Jakmab881c702010-11-23 16:35:42 +00001309 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001310 {
1311 /* ignore */
1312 if ( BGP_DEBUG(as4, AS4))
1313 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1314 " send AGGREGATOR != AS_TRANS and"
1315 " AS4_AGGREGATOR, so ignore"
1316 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1317 ignore_as4_path = 1;
1318 }
1319 else
1320 {
1321 /* "New_aggregator shall be taken as aggregator" */
1322 attre->aggregator_as = as4_aggregator;
1323 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1324 }
1325 }
1326 else
1327 {
1328 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1329 * That is bogus - but reading the conditions
1330 * we have to handle AS4_AGGREGATOR as if it were
1331 * AGGREGATOR in that case
1332 */
1333 if ( BGP_DEBUG(as4, AS4))
1334 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1335 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1336 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001337 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001338 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1339 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1340 }
1341 }
1342
1343 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001344 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001345 {
1346 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001347 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001348 attr->aspath = aspath_intern (newpath);
1349 }
Paul Jakmab881c702010-11-23 16:35:42 +00001350 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001351}
1352
paul718e3742002-12-13 20:15:29 +00001353/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001354static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001355bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001356{
Paul Jakma835315b2012-01-18 12:28:30 +00001357 struct peer *const peer = args->peer;
1358 struct attr *const attr = args->attr;
1359 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001360
paul718e3742002-12-13 20:15:29 +00001361 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001362 {
1363 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001364 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001365 }
Paul Jakma0c466382010-12-05 17:17:26 +00001366
1367 attr->community =
1368 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1369
1370 /* XXX: fix community_parse to use stream API and remove this */
1371 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001372
Paul Jakma0c466382010-12-05 17:17:26 +00001373 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001374 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001375 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001376 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001377
paul718e3742002-12-13 20:15:29 +00001378 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1379
Paul Jakmab881c702010-11-23 16:35:42 +00001380 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001381}
1382
1383/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001384static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001385bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001386{
Paul Jakma835315b2012-01-18 12:28:30 +00001387 struct peer *const peer = args->peer;
1388 struct attr *const attr = args->attr;
1389 const bgp_size_t length = args->length;
1390
Denis Ovsienkod595b562011-09-30 15:08:54 +04001391 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001392 if (length != 4)
1393 {
1394 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1395
Paul Jakma835315b2012-01-18 12:28:30 +00001396 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001397 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001398 args->total);
paul718e3742002-12-13 20:15:29 +00001399 }
1400
Paul Jakmafb982c22007-05-04 20:15:47 +00001401 (bgp_attr_extra_get (attr))->originator_id.s_addr
1402 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001403
1404 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1405
Paul Jakmab881c702010-11-23 16:35:42 +00001406 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001407}
1408
1409/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001410static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001411bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001412{
Paul Jakma835315b2012-01-18 12:28:30 +00001413 struct peer *const peer = args->peer;
1414 struct attr *const attr = args->attr;
1415 const bgp_size_t length = args->length;
1416
paul718e3742002-12-13 20:15:29 +00001417 /* Check length. */
1418 if (length % 4)
1419 {
1420 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1421
Paul Jakma835315b2012-01-18 12:28:30 +00001422 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1423 args->total);
paul718e3742002-12-13 20:15:29 +00001424 }
1425
Paul Jakmafb982c22007-05-04 20:15:47 +00001426 (bgp_attr_extra_get (attr))->cluster
1427 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001428
1429 /* XXX: Fix cluster_parse to use stream API and then remove this */
1430 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001431
1432 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1433
Paul Jakmab881c702010-11-23 16:35:42 +00001434 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001435}
1436
1437/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001438int
Paul Jakma835315b2012-01-18 12:28:30 +00001439bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1440 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001441{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001442 afi_t afi;
1443 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001444 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001445 size_t start;
paul718e3742002-12-13 20:15:29 +00001446 int ret;
1447 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001448 struct peer *const peer = args->peer;
1449 struct attr *const attr = args->attr;
1450 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001451 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001452
paul718e3742002-12-13 20:15:29 +00001453 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001454 s = BGP_INPUT(peer);
1455 start = stream_get_getp(s);
1456
1457 /* safe to read statically sized header? */
1458#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001459#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001460 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001461 {
1462 zlog_info ("%s: %s sent invalid length, %lu",
1463 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001464 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001465 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001466
paul718e3742002-12-13 20:15:29 +00001467 /* Load AFI, SAFI. */
1468 afi = stream_getw (s);
1469 safi = stream_getc (s);
1470
1471 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001472 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001473
Paul Jakma03292802008-06-07 20:37:10 +00001474 if (LEN_LEFT < attre->mp_nexthop_len)
1475 {
1476 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1477 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001478 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001479 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001480
paul718e3742002-12-13 20:15:29 +00001481 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001482 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001483 {
1484 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001485 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001486 /* Probably needed for RFC 2283 */
1487 if (attr->nexthop.s_addr == 0)
1488 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001489 break;
1490 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001491 stream_getl (s); /* RD high */
1492 stream_getl (s); /* RD low */
1493 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001494 break;
1495#ifdef HAVE_IPV6
1496 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001497 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001498 break;
1499 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001500 stream_get (&attre->mp_nexthop_global, s, 16);
1501 stream_get (&attre->mp_nexthop_local, s, 16);
1502 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001503 {
1504 char buf1[INET6_ADDRSTRLEN];
1505 char buf2[INET6_ADDRSTRLEN];
1506
1507 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001508 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 +00001509 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001510 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001511 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001512 buf2, INET6_ADDRSTRLEN));
1513
Paul Jakmafb982c22007-05-04 20:15:47 +00001514 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001515 }
1516 break;
1517#endif /* HAVE_IPV6 */
1518 default:
Paul Jakma03292802008-06-07 20:37:10 +00001519 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1520 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001521 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001522 }
1523
Paul Jakma03292802008-06-07 20:37:10 +00001524 if (!LEN_LEFT)
1525 {
1526 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1527 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001528 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001529 }
paul718e3742002-12-13 20:15:29 +00001530
Paul Jakma6e4ab122007-04-10 19:36:48 +00001531 {
1532 u_char val;
1533 if ((val = stream_getc (s)))
1534 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1535 peer->host, val);
1536 }
1537
1538 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001539 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001540 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001541 {
1542 zlog_info ("%s: (%s) Failed to read NLRI",
1543 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001544 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001545 }
paul718e3742002-12-13 20:15:29 +00001546
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001547 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001548 {
1549 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001550 if (ret < 0)
1551 {
1552 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1553 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001554 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001555 }
paul718e3742002-12-13 20:15:29 +00001556 }
1557
1558 mp_update->afi = afi;
1559 mp_update->safi = safi;
1560 mp_update->nlri = stream_pnt (s);
1561 mp_update->length = nlri_len;
1562
paul9985f832005-02-09 15:51:56 +00001563 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001564
Paul Jakmab881c702010-11-23 16:35:42 +00001565 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001566#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001567}
1568
1569/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001570int
Paul Jakma835315b2012-01-18 12:28:30 +00001571bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001572 struct bgp_nlri *mp_withdraw)
1573{
1574 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001575 afi_t afi;
1576 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001577 u_int16_t withdraw_len;
1578 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001579 struct peer *const peer = args->peer;
1580 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001581
1582 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001583
1584#define BGP_MP_UNREACH_MIN_SIZE 3
1585 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001586 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001587
paul718e3742002-12-13 20:15:29 +00001588 afi = stream_getw (s);
1589 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001590
1591 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001592
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001593 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001594 {
1595 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1596 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001597 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001598 }
1599
1600 mp_withdraw->afi = afi;
1601 mp_withdraw->safi = safi;
1602 mp_withdraw->nlri = stream_pnt (s);
1603 mp_withdraw->length = withdraw_len;
1604
paul9985f832005-02-09 15:51:56 +00001605 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001606
Paul Jakmab881c702010-11-23 16:35:42 +00001607 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001608}
1609
1610/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001611static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001612bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001613{
Paul Jakma835315b2012-01-18 12:28:30 +00001614 struct peer *const peer = args->peer;
1615 struct attr *const attr = args->attr;
1616 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001617
paul718e3742002-12-13 20:15:29 +00001618 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001619 {
1620 if (attr->extra)
1621 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001622 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001623 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001624 }
Paul Jakma0c466382010-12-05 17:17:26 +00001625
1626 (bgp_attr_extra_get (attr))->ecommunity =
1627 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1628 /* XXX: fix ecommunity_parse to use stream API */
1629 stream_forward_getp (peer->ibuf, length);
1630
1631 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001632 return bgp_attr_malformed (args,
1633 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1634 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001635
paul718e3742002-12-13 20:15:29 +00001636 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1637
Paul Jakmab881c702010-11-23 16:35:42 +00001638 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001639}
1640
1641/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001642static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001643bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001644{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001645 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001646 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001647 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001648 struct peer *const peer = args->peer;
1649 struct attr *const attr = args->attr;
1650 u_char *const startp = args->startp;
1651 const u_char type = args->type;
1652 const u_char flag = args->flags;
1653 const bgp_size_t length = args->length;
1654
paul718e3742002-12-13 20:15:29 +00001655
hassof4184462005-02-01 20:13:16 +00001656 if (BGP_DEBUG (normal, NORMAL))
1657 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1658 peer->host, type, length);
1659
paul718e3742002-12-13 20:15:29 +00001660 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001661 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001662 "Unknown attribute type %d length %d is received", type, length);
1663
1664 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001665 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001666
paul718e3742002-12-13 20:15:29 +00001667 /* If any of the mandatory well-known attributes are not recognized,
1668 then the Error Subcode is set to Unrecognized Well-known
1669 Attribute. The Data field contains the unrecognized attribute
1670 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001671 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001672 {
Paul Jakma835315b2012-01-18 12:28:30 +00001673 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001674 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001675 args->total);
paul718e3742002-12-13 20:15:29 +00001676 }
1677
1678 /* Unrecognized non-transitive optional attributes must be quietly
1679 ignored and not passed along to other BGP peers. */
1680 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001681 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001682
1683 /* If a path with recognized transitive optional attribute is
1684 accepted and passed along to other BGP peers and the Partial bit
1685 in the Attribute Flags octet is set to 1 by some previous AS, it
1686 is not set back to 0 by the current AS. */
1687 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1688
1689 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001690 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001691 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001692
Paul Jakmafb982c22007-05-04 20:15:47 +00001693 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001694
1695 if (transit->val)
1696 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1697 transit->length + total);
1698 else
1699 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1700
1701 memcpy (transit->val + transit->length, startp, total);
1702 transit->length += total;
1703
Paul Jakmab881c702010-11-23 16:35:42 +00001704 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001705}
1706
1707/* Read attribute of update packet. This function is called from
1708 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001709bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001710bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1711 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1712{
1713 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001714 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001715 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001716 bgp_size_t length;
1717 u_char *startp, *endp;
1718 u_char *attr_endp;
1719 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001720 /* we need the as4_path only until we have synthesized the as_path with it */
1721 /* same goes for as4_aggregator */
1722 struct aspath *as4_path = NULL;
1723 as_t as4_aggregator = 0;
1724 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001725
1726 /* Initialize bitmap. */
1727 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1728
1729 /* End pointer of BGP attribute. */
1730 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001731
paul718e3742002-12-13 20:15:29 +00001732 /* Get attributes to the end of attribute length. */
1733 while (BGP_INPUT_PNT (peer) < endp)
1734 {
1735 /* Check remaining length check.*/
1736 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1737 {
gdtc29fdba2004-12-09 14:46:46 +00001738 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001739 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001740 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001741 peer->host,
1742 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001743
1744 bgp_notify_send (peer,
1745 BGP_NOTIFY_UPDATE_ERR,
1746 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001747 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001748 }
1749
1750 /* Fetch attribute flag and type. */
1751 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001752 /* "The lower-order four bits of the Attribute Flags octet are
1753 unused. They MUST be zero when sent and MUST be ignored when
1754 received." */
1755 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001756 type = stream_getc (BGP_INPUT (peer));
1757
Paul Jakma370b64a2007-12-22 16:49:52 +00001758 /* Check whether Extended-Length applies and is in bounds */
1759 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1760 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1761 {
1762 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001763 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001764 peer->host,
1765 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1766
1767 bgp_notify_send (peer,
1768 BGP_NOTIFY_UPDATE_ERR,
1769 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001770 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001771 }
Paul Jakma835315b2012-01-18 12:28:30 +00001772
paul718e3742002-12-13 20:15:29 +00001773 /* Check extended attribue length bit. */
1774 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1775 length = stream_getw (BGP_INPUT (peer));
1776 else
1777 length = stream_getc (BGP_INPUT (peer));
1778
1779 /* If any attribute appears more than once in the UPDATE
1780 message, then the Error Subcode is set to Malformed Attribute
1781 List. */
1782
1783 if (CHECK_BITMAP (seen, type))
1784 {
1785 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001786 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001787 peer->host, type);
1788
1789 bgp_notify_send (peer,
1790 BGP_NOTIFY_UPDATE_ERR,
1791 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001792 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001793 }
1794
1795 /* Set type to bitmap to check duplicate attribute. `type' is
1796 unsigned char so it never overflow bitmap range. */
1797
1798 SET_BITMAP (seen, type);
1799
1800 /* Overflow check. */
1801 attr_endp = BGP_INPUT_PNT (peer) + length;
1802
1803 if (attr_endp > endp)
1804 {
1805 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001806 "%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 +00001807 bgp_notify_send (peer,
1808 BGP_NOTIFY_UPDATE_ERR,
1809 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001810 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001811 }
Paul Jakma835315b2012-01-18 12:28:30 +00001812
1813 struct bgp_attr_parser_args attr_args = {
1814 .peer = peer,
1815 .length = length,
1816 .attr = attr,
1817 .type = type,
1818 .flags = flag,
1819 .startp = startp,
1820 .total = attr_endp - startp,
1821 };
1822
1823
1824 /* If any recognized attribute has Attribute Flags that conflict
1825 with the Attribute Type Code, then the Error Subcode is set to
1826 Attribute Flags Error. The Data field contains the erroneous
1827 attribute (type, length and value). */
1828 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001829 {
1830 bgp_attr_parse_ret_t ret;
1831 ret = bgp_attr_malformed (&attr_args,
1832 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1833 attr_args.total);
1834 if (ret == BGP_ATTR_PARSE_PROCEED)
1835 continue;
1836 return ret;
1837 }
paul718e3742002-12-13 20:15:29 +00001838
1839 /* OK check attribute and store it's value. */
1840 switch (type)
1841 {
1842 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001843 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001844 break;
1845 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001846 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001847 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001848 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001849 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001850 break;
paul718e3742002-12-13 20:15:29 +00001851 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001852 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001853 break;
1854 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001855 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001856 break;
1857 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001858 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001859 break;
1860 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001861 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001862 break;
1863 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001864 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001865 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001866 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001867 ret = bgp_attr_as4_aggregator (&attr_args,
1868 &as4_aggregator,
1869 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001870 break;
paul718e3742002-12-13 20:15:29 +00001871 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001872 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001873 break;
1874 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001875 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001876 break;
1877 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001878 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001879 break;
1880 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001881 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001882 break;
1883 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001884 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001885 break;
1886 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001887 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001888 break;
1889 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001890 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001891 break;
1892 }
Paul Jakmab881c702010-11-23 16:35:42 +00001893
1894 /* If hard error occured immediately return to the caller. */
1895 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001896 {
1897 zlog (peer->log, LOG_WARNING,
1898 "%s: Attribute %s, parse error",
1899 peer->host,
1900 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001901 bgp_notify_send (peer,
1902 BGP_NOTIFY_UPDATE_ERR,
1903 BGP_NOTIFY_UPDATE_MAL_ATTR);
1904 if (as4_path)
1905 aspath_unintern (&as4_path);
1906 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001907 }
Paul Jakmab881c702010-11-23 16:35:42 +00001908 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1909 {
1910
1911 zlog (peer->log, LOG_WARNING,
1912 "%s: Attribute %s, parse error - treating as withdrawal",
1913 peer->host,
1914 LOOKUP (attr_str, type));
1915 if (as4_path)
1916 aspath_unintern (&as4_path);
1917 return ret;
1918 }
1919
paul718e3742002-12-13 20:15:29 +00001920 /* Check the fetched length. */
1921 if (BGP_INPUT_PNT (peer) != attr_endp)
1922 {
1923 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001924 "%s: BGP attribute %s, fetch error",
1925 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001926 bgp_notify_send (peer,
1927 BGP_NOTIFY_UPDATE_ERR,
1928 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001929 if (as4_path)
1930 aspath_unintern (&as4_path);
1931 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001932 }
1933 }
1934
1935 /* Check final read pointer is same as end pointer. */
1936 if (BGP_INPUT_PNT (peer) != endp)
1937 {
1938 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001939 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001940 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001941 bgp_notify_send (peer,
1942 BGP_NOTIFY_UPDATE_ERR,
1943 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001944 if (as4_path)
1945 aspath_unintern (&as4_path);
1946 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001947 }
1948
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001949 /*
1950 * At this place we can see whether we got AS4_PATH and/or
1951 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1952 * We can not do this before we've read all attributes because
1953 * the as4 handling does not say whether AS4_PATH has to be sent
1954 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1955 * in relationship to AGGREGATOR.
1956 * So, to be defensive, we are not relying on any order and read
1957 * all attributes first, including these 32bit ones, and now,
1958 * afterwards, we look what and if something is to be done for as4.
1959 */
Paul Jakma835315b2012-01-18 12:28:30 +00001960 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001961 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001962 {
1963 if (as4_path)
1964 aspath_unintern (&as4_path);
1965 return BGP_ATTR_PARSE_ERROR;
1966 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001967
1968 /* At this stage, we have done all fiddling with as4, and the
1969 * resulting info is in attr->aggregator resp. attr->aspath
1970 * so we can chuck as4_aggregator and as4_path alltogether in
1971 * order to save memory
1972 */
Paul Jakmab881c702010-11-23 16:35:42 +00001973 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001974 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001975 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001976 /* The flag that we got this is still there, but that does not
1977 * do any trouble
1978 */
1979 }
1980 /*
1981 * The "rest" of the code does nothing with as4_aggregator.
1982 * there is no memory attached specifically which is not part
1983 * of the attr.
1984 * so ignoring just means do nothing.
1985 */
1986 /*
1987 * Finally do the checks on the aspath we did not do yet
1988 * because we waited for a potentially synthesized aspath.
1989 */
Paul Jakmab881c702010-11-23 16:35:42 +00001990 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001991 {
Paul Jakma835315b2012-01-18 12:28:30 +00001992 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001993 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001994 return ret;
1995 }
1996
paul718e3742002-12-13 20:15:29 +00001997 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001998 if (attr->extra && attr->extra->transit)
1999 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002000
Paul Jakmab881c702010-11-23 16:35:42 +00002001 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002002}
2003
2004/* Well-known attribute check. */
2005int
2006bgp_attr_check (struct peer *peer, struct attr *attr)
2007{
2008 u_char type = 0;
2009
2010 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2011 type = BGP_ATTR_ORIGIN;
2012
2013 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2014 type = BGP_ATTR_AS_PATH;
2015
2016 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2017 type = BGP_ATTR_NEXT_HOP;
2018
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002019 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002020 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2021 type = BGP_ATTR_LOCAL_PREF;
2022
2023 if (type)
2024 {
2025 zlog (peer->log, LOG_WARNING,
2026 "%s Missing well-known attribute %d.",
2027 peer->host, type);
2028 bgp_notify_send_with_data (peer,
2029 BGP_NOTIFY_UPDATE_ERR,
2030 BGP_NOTIFY_UPDATE_MISS_ATTR,
2031 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002032 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002033 }
Paul Jakmab881c702010-11-23 16:35:42 +00002034 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002035}
2036
2037int stream_put_prefix (struct stream *, struct prefix *);
2038
2039/* Make attribute packet. */
2040bgp_size_t
2041bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2042 struct stream *s, struct attr *attr, struct prefix *p,
2043 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002044 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002045{
paulfe69a502005-09-10 16:55:02 +00002046 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002047 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002048 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002049 int send_as4_path = 0;
2050 int send_as4_aggregator = 0;
2051 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002052
2053 if (! bgp)
2054 bgp = bgp_get_default ();
2055
2056 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002057 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002058
2059 /* Origin attribute. */
2060 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2061 stream_putc (s, BGP_ATTR_ORIGIN);
2062 stream_putc (s, 1);
2063 stream_putc (s, attr->origin);
2064
2065 /* AS path attribute. */
2066
2067 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002068 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002069 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002070 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002071 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002072 {
2073 aspath = aspath_dup (attr->aspath);
2074
2075 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2076 {
2077 /* Strip the confed info, and then stuff our path CONFED_ID
2078 on the front */
2079 aspath = aspath_delete_confed_seq (aspath);
2080 aspath = aspath_add_seq (aspath, bgp->confed_id);
2081 }
2082 else
2083 {
2084 aspath = aspath_add_seq (aspath, peer->local_as);
2085 if (peer->change_local_as)
2086 aspath = aspath_add_seq (aspath, peer->change_local_as);
2087 }
2088 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002089 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002090 {
2091 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2092 aspath = aspath_dup (attr->aspath);
2093 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2094 }
2095 else
2096 aspath = attr->aspath;
2097
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002098 /* If peer is not AS4 capable, then:
2099 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2100 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2101 * types are in it (i.e. exclude them if they are there)
2102 * AND do this only if there is at least one asnum > 65535 in the path!
2103 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2104 * all ASnums > 65535 to BGP_AS_TRANS
2105 */
paul718e3742002-12-13 20:15:29 +00002106
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002107 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2108 stream_putc (s, BGP_ATTR_AS_PATH);
2109 aspath_sizep = stream_get_endp (s);
2110 stream_putw (s, 0);
2111 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2112
2113 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2114 * in the path
2115 */
2116 if (!use32bit && aspath_has_as4 (aspath))
2117 send_as4_path = 1; /* we'll do this later, at the correct place */
2118
paul718e3742002-12-13 20:15:29 +00002119 /* Nexthop attribute. */
2120 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2121 {
2122 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2123 stream_putc (s, BGP_ATTR_NEXT_HOP);
2124 stream_putc (s, 4);
2125 if (safi == SAFI_MPLS_VPN)
2126 {
2127 if (attr->nexthop.s_addr == 0)
2128 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2129 else
2130 stream_put_ipv4 (s, attr->nexthop.s_addr);
2131 }
2132 else
2133 stream_put_ipv4 (s, attr->nexthop.s_addr);
2134 }
2135
2136 /* MED attribute. */
2137 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2138 {
2139 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2140 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2141 stream_putc (s, 4);
2142 stream_putl (s, attr->med);
2143 }
2144
2145 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002146 if (peer->sort == BGP_PEER_IBGP ||
2147 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002148 {
2149 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2150 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2151 stream_putc (s, 4);
2152 stream_putl (s, attr->local_pref);
2153 }
2154
2155 /* Atomic aggregate. */
2156 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2157 {
2158 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2159 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2160 stream_putc (s, 0);
2161 }
2162
2163 /* Aggregator. */
2164 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2165 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002166 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002167
2168 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002169 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2170 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002171
2172 if (use32bit)
2173 {
2174 /* AS4 capable peer */
2175 stream_putc (s, 8);
2176 stream_putl (s, attr->extra->aggregator_as);
2177 }
2178 else
2179 {
2180 /* 2-byte AS peer */
2181 stream_putc (s, 6);
2182
2183 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2184 if ( attr->extra->aggregator_as > 65535 )
2185 {
2186 stream_putw (s, BGP_AS_TRANS);
2187
2188 /* we have to send AS4_AGGREGATOR, too.
2189 * we'll do that later in order to send attributes in ascending
2190 * order.
2191 */
2192 send_as4_aggregator = 1;
2193 }
2194 else
2195 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2196 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002197 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002198 }
2199
2200 /* Community attribute. */
2201 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2202 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2203 {
2204 if (attr->community->size * 4 > 255)
2205 {
2206 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2207 stream_putc (s, BGP_ATTR_COMMUNITIES);
2208 stream_putw (s, attr->community->size * 4);
2209 }
2210 else
2211 {
2212 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2213 stream_putc (s, BGP_ATTR_COMMUNITIES);
2214 stream_putc (s, attr->community->size * 4);
2215 }
2216 stream_put (s, attr->community->val, attr->community->size * 4);
2217 }
2218
2219 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002220 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002221 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002222 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002223 {
2224 /* Originator ID. */
2225 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2226 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2227 stream_putc (s, 4);
2228
2229 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002230 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002231 else
2232 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002233
2234 /* Cluster list. */
2235 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2236 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2237
Paul Jakma9eda90c2007-08-30 13:36:17 +00002238 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002239 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002240 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002241 /* If this peer configuration's parent BGP has cluster_id. */
2242 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2243 stream_put_in_addr (s, &bgp->cluster_id);
2244 else
2245 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002246 stream_put (s, attr->extra->cluster->list,
2247 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002248 }
2249 else
2250 {
2251 stream_putc (s, 4);
2252 /* If this peer configuration's parent BGP has cluster_id. */
2253 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2254 stream_put_in_addr (s, &bgp->cluster_id);
2255 else
2256 stream_put_in_addr (s, &bgp->router_id);
2257 }
2258 }
2259
2260#ifdef HAVE_IPV6
2261 /* If p is IPv6 address put it into attribute. */
2262 if (p->family == AF_INET6)
2263 {
2264 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002265 struct attr_extra *attre = attr->extra;
2266
2267 assert (attr->extra);
2268
paul718e3742002-12-13 20:15:29 +00002269 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2270 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002271 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002272 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002273 stream_putw (s, AFI_IP6); /* AFI */
2274 stream_putc (s, safi); /* SAFI */
2275
Paul Jakmafb982c22007-05-04 20:15:47 +00002276 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002277
Paul Jakmafb982c22007-05-04 20:15:47 +00002278 if (attre->mp_nexthop_len == 16)
2279 stream_put (s, &attre->mp_nexthop_global, 16);
2280 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002281 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002282 stream_put (s, &attre->mp_nexthop_global, 16);
2283 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002284 }
2285
2286 /* SNPA */
2287 stream_putc (s, 0);
2288
paul718e3742002-12-13 20:15:29 +00002289 /* Prefix write. */
2290 stream_put_prefix (s, p);
2291
2292 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002293 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002294 }
2295#endif /* HAVE_IPV6 */
2296
2297 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2298 {
2299 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002300
2301 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2302 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002303 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002304 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002305 stream_putw (s, AFI_IP); /* AFI */
2306 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2307
2308 stream_putc (s, 4);
2309 stream_put_ipv4 (s, attr->nexthop.s_addr);
2310
2311 /* SNPA */
2312 stream_putc (s, 0);
2313
paul718e3742002-12-13 20:15:29 +00002314 /* Prefix write. */
2315 stream_put_prefix (s, p);
2316
2317 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002318 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002319 }
2320
2321 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2322 {
2323 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002324
2325 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2326 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002327 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002328 stream_putc (s, 0); /* Length of this attribute. */
2329 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002330 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002331
2332 stream_putc (s, 12);
2333 stream_putl (s, 0);
2334 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002335 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002336
2337 /* SNPA */
2338 stream_putc (s, 0);
2339
paul718e3742002-12-13 20:15:29 +00002340 /* Tag, RD, Prefix write. */
2341 stream_putc (s, p->prefixlen + 88);
2342 stream_put (s, tag, 3);
2343 stream_put (s, prd->val, 8);
2344 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2345
2346 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002347 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002348 }
2349
2350 /* Extended Communities attribute. */
2351 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2352 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2353 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002354 struct attr_extra *attre = attr->extra;
2355
2356 assert (attre);
2357
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002358 if (peer->sort == BGP_PEER_IBGP
2359 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002360 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002361 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002362 {
2363 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2364 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002365 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002366 }
2367 else
2368 {
2369 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2370 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002371 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002372 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002373 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002374 }
2375 else
2376 {
paul5228ad22004-06-04 17:58:18 +00002377 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002378 int tbit;
2379 int ecom_tr_size = 0;
2380 int i;
2381
Paul Jakmafb982c22007-05-04 20:15:47 +00002382 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002383 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002384 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002385 tbit = *pnt;
2386
2387 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2388 continue;
2389
2390 ecom_tr_size++;
2391 }
2392
2393 if (ecom_tr_size)
2394 {
2395 if (ecom_tr_size * 8 > 255)
2396 {
2397 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2398 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2399 stream_putw (s, ecom_tr_size * 8);
2400 }
2401 else
2402 {
2403 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2404 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2405 stream_putc (s, ecom_tr_size * 8);
2406 }
2407
Paul Jakmafb982c22007-05-04 20:15:47 +00002408 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002409 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002410 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002411 tbit = *pnt;
2412
2413 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2414 continue;
2415
2416 stream_put (s, pnt, 8);
2417 }
2418 }
paul718e3742002-12-13 20:15:29 +00002419 }
paul718e3742002-12-13 20:15:29 +00002420 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002421
2422 if ( send_as4_path )
2423 {
2424 /* If the peer is NOT As4 capable, AND */
2425 /* there are ASnums > 65535 in path THEN
2426 * give out AS4_PATH */
2427
2428 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2429 * path segments!
2430 * Hm, I wonder... confederation things *should* only be at
2431 * the beginning of an aspath, right? Then we should use
2432 * aspath_delete_confed_seq for this, because it is already
2433 * there! (JK)
2434 * Folks, talk to me: what is reasonable here!?
2435 */
2436 aspath = aspath_delete_confed_seq (aspath);
2437
2438 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2439 stream_putc (s, BGP_ATTR_AS4_PATH);
2440 aspath_sizep = stream_get_endp (s);
2441 stream_putw (s, 0);
2442 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2443 }
2444
2445 if (aspath != attr->aspath)
2446 aspath_free (aspath);
2447
2448 if ( send_as4_aggregator )
2449 {
2450 assert (attr->extra);
2451
2452 /* send AS4_AGGREGATOR, at this place */
2453 /* this section of code moved here in order to ensure the correct
2454 * *ascending* order of attributes
2455 */
2456 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2457 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2458 stream_putc (s, 8);
2459 stream_putl (s, attr->extra->aggregator_as);
2460 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2461 }
Paul Jakma41367172007-08-06 15:24:51 +00002462
paul718e3742002-12-13 20:15:29 +00002463 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002464 if (attr->extra && attr->extra->transit)
2465 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002466
2467 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002468 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002469}
2470
2471bgp_size_t
2472bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2473 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002474 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002475{
2476 unsigned long cp;
2477 unsigned long attrlen_pnt;
2478 bgp_size_t size;
2479
paul9985f832005-02-09 15:51:56 +00002480 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002481
2482 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2483 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2484
paul9985f832005-02-09 15:51:56 +00002485 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002486 stream_putc (s, 0); /* Length of this attribute. */
2487
2488 stream_putw (s, family2afi (p->family));
2489
2490 if (safi == SAFI_MPLS_VPN)
2491 {
2492 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002493 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002494
2495 /* prefix. */
2496 stream_putc (s, p->prefixlen + 88);
2497 stream_put (s, tag, 3);
2498 stream_put (s, prd->val, 8);
2499 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2500 }
2501 else
2502 {
2503 /* SAFI */
2504 stream_putc (s, safi);
2505
2506 /* prefix */
2507 stream_put_prefix (s, p);
2508 }
2509
2510 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002511 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002512 stream_putc_at (s, attrlen_pnt, size);
2513
paul9985f832005-02-09 15:51:56 +00002514 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002515}
2516
2517/* Initialization of attribute. */
2518void
paulfe69a502005-09-10 16:55:02 +00002519bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002520{
paul718e3742002-12-13 20:15:29 +00002521 aspath_init ();
2522 attrhash_init ();
2523 community_init ();
2524 ecommunity_init ();
2525 cluster_init ();
2526 transit_init ();
2527}
2528
Chris Caputo228da422009-07-18 05:44:03 +00002529void
2530bgp_attr_finish (void)
2531{
2532 aspath_finish ();
2533 attrhash_finish ();
2534 community_finish ();
2535 ecommunity_finish ();
2536 cluster_finish ();
2537 transit_finish ();
2538}
2539
paul718e3742002-12-13 20:15:29 +00002540/* Make attribute packet. */
2541void
paula3845922003-10-18 01:30:50 +00002542bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2543 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002544{
2545 unsigned long cp;
2546 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002547 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002548 struct aspath *aspath;
2549
2550 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002551 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002552
2553 /* Place holder of length. */
2554 stream_putw (s, 0);
2555
2556 /* Origin attribute. */
2557 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2558 stream_putc (s, BGP_ATTR_ORIGIN);
2559 stream_putc (s, 1);
2560 stream_putc (s, attr->origin);
2561
2562 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002563
2564 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2565 stream_putc (s, BGP_ATTR_AS_PATH);
2566 aspath_lenp = stream_get_endp (s);
2567 stream_putw (s, 0);
2568
2569 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002570
2571 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002572 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2573 if(prefix != NULL
2574#ifdef HAVE_IPV6
2575 && prefix->family != AF_INET6
2576#endif /* HAVE_IPV6 */
2577 )
2578 {
2579 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2580 stream_putc (s, BGP_ATTR_NEXT_HOP);
2581 stream_putc (s, 4);
2582 stream_put_ipv4 (s, attr->nexthop.s_addr);
2583 }
paul718e3742002-12-13 20:15:29 +00002584
2585 /* MED attribute. */
2586 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2587 {
2588 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2589 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2590 stream_putc (s, 4);
2591 stream_putl (s, attr->med);
2592 }
2593
2594 /* Local preference. */
2595 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2596 {
2597 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2598 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2599 stream_putc (s, 4);
2600 stream_putl (s, attr->local_pref);
2601 }
2602
2603 /* Atomic aggregate. */
2604 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2605 {
2606 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2607 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2608 stream_putc (s, 0);
2609 }
2610
2611 /* Aggregator. */
2612 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2613 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002614 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002615 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2616 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002617 stream_putc (s, 8);
2618 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002619 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002620 }
2621
2622 /* Community attribute. */
2623 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2624 {
2625 if (attr->community->size * 4 > 255)
2626 {
2627 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2628 stream_putc (s, BGP_ATTR_COMMUNITIES);
2629 stream_putw (s, attr->community->size * 4);
2630 }
2631 else
2632 {
2633 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2634 stream_putc (s, BGP_ATTR_COMMUNITIES);
2635 stream_putc (s, attr->community->size * 4);
2636 }
2637 stream_put (s, attr->community->val, attr->community->size * 4);
2638 }
2639
paula3845922003-10-18 01:30:50 +00002640#ifdef HAVE_IPV6
2641 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002642 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2643 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002644 {
2645 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002646 struct attr_extra *attre = attr->extra;
2647
paula3845922003-10-18 01:30:50 +00002648 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2649 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002650 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002651
2652 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002653 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002654 stream_putw(s, AFI_IP6); /* AFI */
2655 stream_putc(s, SAFI_UNICAST); /* SAFI */
2656
2657 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002658 stream_putc(s, attre->mp_nexthop_len);
2659 stream_put(s, &attre->mp_nexthop_global, 16);
2660 if (attre->mp_nexthop_len == 32)
2661 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002662
2663 /* SNPA */
2664 stream_putc(s, 0);
2665
2666 /* Prefix */
2667 stream_put_prefix(s, prefix);
2668
2669 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002670 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002671 }
2672#endif /* HAVE_IPV6 */
2673
paul718e3742002-12-13 20:15:29 +00002674 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002675 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002676 stream_putw_at (s, cp, len);
2677}