blob: 2d82acc227801ece7031f7106898be5463338a5c [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{
Jorge Boncompte [DTI2]558d1fe2012-05-07 16:53:05 +0000322 struct attr_extra *extra = new->extra;
323
Paul Jakmafb982c22007-05-04 20:15:47 +0000324 *new = *orig;
325 if (orig->extra)
326 {
Jorge Boncompte [DTI2]558d1fe2012-05-07 16:53:05 +0000327 /* if caller provided attr_extra space use it */
328 if (! extra)
329 new->extra = bgp_attr_extra_new();
Paul Jakmafb982c22007-05-04 20:15:47 +0000330 *new->extra = *orig->extra;
331 }
332}
333
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000334unsigned long int
335attr_count (void)
336{
337 return attrhash->count;
338}
339
340unsigned long int
341attr_unknown_count (void)
342{
343 return transit_hash->count;
344}
345
paul718e3742002-12-13 20:15:29 +0000346unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000347attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000348{
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000349 const struct attr *attr = (struct attr *) p;
350 const struct attr_extra *extra = attr->extra;
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700351 uint32_t key = 0;
352#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000353
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700354 MIX(attr->origin);
355 MIX(attr->nexthop.s_addr);
356 MIX(attr->med);
357 MIX(attr->local_pref);
358
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000359 key += attr->origin;
360 key += attr->nexthop.s_addr;
361 key += attr->med;
362 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000363
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000364 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000365 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000366 MIX(extra->aggregator_as);
367 MIX(extra->aggregator_addr.s_addr);
368 MIX(extra->weight);
369 MIX(extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000370 }
371
paul718e3742002-12-13 20:15:29 +0000372 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700373 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000374 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700375 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000376
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000377 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000378 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000379 if (extra->ecommunity)
380 MIX(ecommunity_hash_make (extra->ecommunity));
381 if (extra->cluster)
382 MIX(cluster_hash_key_make (extra->cluster));
383 if (extra->transit)
384 MIX(transit_hash_key_make (extra->transit));
paul718e3742002-12-13 20:15:29 +0000385
386#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000387 MIX(extra->mp_nexthop_len);
388 key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
389 key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000390#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000391 }
paul718e3742002-12-13 20:15:29 +0000392
393 return key;
394}
395
396int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100397attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000398{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100399 const struct attr * attr1 = p1;
400 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000401
paul718e3742002-12-13 20:15:29 +0000402 if (attr1->flag == attr2->flag
403 && attr1->origin == attr2->origin
404 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000405 && attr1->aspath == attr2->aspath
406 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000407 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000408 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000409 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100410 const struct attr_extra *ae1 = attr1->extra;
411 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000412
413 if (ae1 && ae2
414 && ae1->aggregator_as == ae2->aggregator_as
415 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
416 && ae1->weight == ae2->weight
417#ifdef HAVE_IPV6
418 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
419 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
420 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
421#endif /* HAVE_IPV6 */
422 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
423 && ae1->ecommunity == ae2->ecommunity
424 && ae1->cluster == ae2->cluster
425 && ae1->transit == ae2->transit)
426 return 1;
427 else if (ae1 || ae2)
428 return 0;
429 /* neither attribute has extra attributes, so they're same */
430 return 1;
431 }
paul718e3742002-12-13 20:15:29 +0000432 else
433 return 0;
434}
435
paul94f2b392005-06-28 12:44:16 +0000436static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100437attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000438{
439 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
440}
441
paul94f2b392005-06-28 12:44:16 +0000442static void
Chris Caputo228da422009-07-18 05:44:03 +0000443attrhash_finish (void)
444{
445 hash_free (attrhash);
446 attrhash = NULL;
447}
448
449static void
paul718e3742002-12-13 20:15:29 +0000450attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
451{
452 struct attr *attr = backet->data;
453
454 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
455 inet_ntoa (attr->nexthop), VTY_NEWLINE);
456}
457
458void
459attr_show_all (struct vty *vty)
460{
461 hash_iterate (attrhash,
462 (void (*)(struct hash_backet *, void *))
463 attr_show_all_iterator,
464 vty);
465}
466
paul94f2b392005-06-28 12:44:16 +0000467static void *
Paul Jakma923de652007-04-29 18:25:17 +0000468bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000469{
Paul Jakma923de652007-04-29 18:25:17 +0000470 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000471 struct attr *attr;
472
473 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
474 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000475 if (val->extra)
476 {
477 attr->extra = bgp_attr_extra_new ();
478 *attr->extra = *val->extra;
479 }
paul718e3742002-12-13 20:15:29 +0000480 attr->refcnt = 0;
481 return attr;
482}
483
484/* Internet argument attribute. */
485struct attr *
486bgp_attr_intern (struct attr *attr)
487{
488 struct attr *find;
489
490 /* Intern referenced strucutre. */
491 if (attr->aspath)
492 {
493 if (! attr->aspath->refcnt)
494 attr->aspath = aspath_intern (attr->aspath);
495 else
496 attr->aspath->refcnt++;
497 }
498 if (attr->community)
499 {
500 if (! attr->community->refcnt)
501 attr->community = community_intern (attr->community);
502 else
503 attr->community->refcnt++;
504 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000505 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000506 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000507 struct attr_extra *attre = attr->extra;
508
509 if (attre->ecommunity)
510 {
511 if (! attre->ecommunity->refcnt)
512 attre->ecommunity = ecommunity_intern (attre->ecommunity);
513 else
514 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000515
Paul Jakmafb982c22007-05-04 20:15:47 +0000516 }
517 if (attre->cluster)
518 {
519 if (! attre->cluster->refcnt)
520 attre->cluster = cluster_intern (attre->cluster);
521 else
522 attre->cluster->refcnt++;
523 }
524 if (attre->transit)
525 {
526 if (! attre->transit->refcnt)
527 attre->transit = transit_intern (attre->transit);
528 else
529 attre->transit->refcnt++;
530 }
paul718e3742002-12-13 20:15:29 +0000531 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000532
paul718e3742002-12-13 20:15:29 +0000533 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
534 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000535
paul718e3742002-12-13 20:15:29 +0000536 return find;
537}
538
Paul Jakma03e214c2007-04-29 18:31:07 +0000539
paul718e3742002-12-13 20:15:29 +0000540/* Make network statement's attribute. */
541struct attr *
542bgp_attr_default_set (struct attr *attr, u_char origin)
543{
544 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000545 bgp_attr_extra_get (attr);
546
paul718e3742002-12-13 20:15:29 +0000547 attr->origin = origin;
548 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
549 attr->aspath = aspath_empty ();
550 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000551 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000552 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
553#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000554 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000555#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000556
paul718e3742002-12-13 20:15:29 +0000557 return attr;
558}
559
Paul Jakma03e214c2007-04-29 18:31:07 +0000560
paul718e3742002-12-13 20:15:29 +0000561/* Make network statement's attribute. */
562struct attr *
563bgp_attr_default_intern (u_char origin)
564{
565 struct attr attr;
566 struct attr *new;
Jorge Boncompte [DTI2]e16a4132012-05-07 16:52:57 +0000567
Paul Jakma03e214c2007-04-29 18:31:07 +0000568 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000569
570 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 bgp_attr_extra_free (&attr);
572
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000573 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000574 return new;
575}
576
577struct attr *
578bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
579 struct aspath *aspath,
580 struct community *community, int as_set)
581{
582 struct attr attr;
583 struct attr *new;
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000584 struct attr_extra attre;
paul718e3742002-12-13 20:15:29 +0000585
586 memset (&attr, 0, sizeof (struct attr));
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000587 memset (&attre, 0, sizeof (struct attr_extra));
588 attr.extra = &attre;
589
paul718e3742002-12-13 20:15:29 +0000590 /* Origin attribute. */
591 attr.origin = origin;
592 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
593
594 /* AS path attribute. */
595 if (aspath)
596 attr.aspath = aspath_intern (aspath);
597 else
598 attr.aspath = aspath_empty ();
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
600
601 /* Next hop attribute. */
602 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
603
604 if (community)
605 {
606 attr.community = community;
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
608 }
609
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000610 attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000611#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000612 attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000613#endif
614 if (! as_set)
615 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
616 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
617 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000618 attre.aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000619 else
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000620 attre.aggregator_as = bgp->as;
621 attre.aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000622
623 new = bgp_attr_intern (&attr);
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000624
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000625 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000626 return new;
627}
628
Paul Jakmab881c702010-11-23 16:35:42 +0000629/* Unintern just the sub-components of the attr, but not the attr */
630void
631bgp_attr_unintern_sub (struct attr *attr)
632{
633 /* aspath refcount shoud be decrement. */
634 if (attr->aspath)
635 aspath_unintern (&attr->aspath);
636 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
637
638 if (attr->community)
639 community_unintern (&attr->community);
640 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
641
642 if (attr->extra)
643 {
644 if (attr->extra->ecommunity)
645 ecommunity_unintern (&attr->extra->ecommunity);
646 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
647
648 if (attr->extra->cluster)
649 cluster_unintern (attr->extra->cluster);
650 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
651
652 if (attr->extra->transit)
653 transit_unintern (attr->extra->transit);
654 }
655}
656
paul718e3742002-12-13 20:15:29 +0000657/* Free bgp attribute and aspath. */
658void
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000659bgp_attr_unintern (struct attr **pattr)
paul718e3742002-12-13 20:15:29 +0000660{
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000661 struct attr *attr = *pattr;
paul718e3742002-12-13 20:15:29 +0000662 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000663 struct attr tmp;
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000664 struct attr_extra tmp_extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000665
paul718e3742002-12-13 20:15:29 +0000666 /* Decrement attribute reference. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000667 attr->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000668
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000669 tmp = *attr;
Paul Jakmab881c702010-11-23 16:35:42 +0000670
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000671 if (attr->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000672 {
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000673 tmp.extra = &tmp_extra;
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000674 memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000675 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000676
paul718e3742002-12-13 20:15:29 +0000677 /* If reference becomes zero then free attribute object. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000678 if (attr->refcnt == 0)
679 {
680 ret = hash_release (attrhash, attr);
paul718e3742002-12-13 20:15:29 +0000681 assert (ret != NULL);
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000682 bgp_attr_extra_free (attr);
683 XFREE (MTYPE_ATTR, attr);
684 *pattr = NULL;
paul718e3742002-12-13 20:15:29 +0000685 }
686
Paul Jakmab881c702010-11-23 16:35:42 +0000687 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000688}
689
690void
691bgp_attr_flush (struct attr *attr)
692{
693 if (attr->aspath && ! attr->aspath->refcnt)
694 aspath_free (attr->aspath);
695 if (attr->community && ! attr->community->refcnt)
696 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000697 if (attr->extra)
698 {
699 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000700
Paul Jakmafb982c22007-05-04 20:15:47 +0000701 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000702 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000703 if (attre->cluster && ! attre->cluster->refcnt)
704 cluster_free (attre->cluster);
705 if (attre->transit && ! attre->transit->refcnt)
706 transit_free (attre->transit);
707 }
paul718e3742002-12-13 20:15:29 +0000708}
709
Paul Jakmab881c702010-11-23 16:35:42 +0000710/* Implement draft-scudder-idr-optional-transitive behaviour and
711 * avoid resetting sessions for malformed attributes which are
712 * are partial/optional and hence where the error likely was not
713 * introduced by the sending neighbour.
714 */
715static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000716bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
717 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000718{
Paul Jakma835315b2012-01-18 12:28:30 +0000719 struct peer *const peer = args->peer;
720 const u_int8_t flags = args->flags;
721 /* startp and length must be special-cased, as whether or not to
722 * send the attribute data with the NOTIFY depends on the error,
723 * the caller therefore signals this with the seperate length argument
724 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000725 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000726
Paul Jakmab881c702010-11-23 16:35:42 +0000727 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000728 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000729 {
730 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000731 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000732 return BGP_ATTR_PARSE_ERROR;
733
734 }
735
Paul Jakmabd471fe2012-03-15 11:30:00 +0000736 /* Adjust the stream getp to the end of the attribute, in case we can
737 * still proceed but the caller hasn't read all the attribute.
738 */
739 stream_set_getp (BGP_INPUT (peer),
740 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
741 + args->total);
742
Paul Jakma835315b2012-01-18 12:28:30 +0000743 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100744 /* where an attribute is relatively inconsequential, e.g. it does not
745 * affect route selection, and can be safely ignored, then any such
746 * attributes which are malformed should just be ignored and the route
747 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000748 */
749 case BGP_ATTR_AS4_AGGREGATOR:
750 case BGP_ATTR_AGGREGATOR:
751 case BGP_ATTR_ATOMIC_AGGREGATE:
752 return BGP_ATTR_PARSE_PROCEED;
753
754 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100755 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000756 */
757 case BGP_ATTR_ORIGIN:
758 case BGP_ATTR_AS_PATH:
759 case BGP_ATTR_NEXT_HOP:
760 case BGP_ATTR_MULTI_EXIT_DISC:
761 case BGP_ATTR_LOCAL_PREF:
762 case BGP_ATTR_COMMUNITIES:
763 case BGP_ATTR_ORIGINATOR_ID:
764 case BGP_ATTR_CLUSTER_LIST:
765 case BGP_ATTR_MP_REACH_NLRI:
766 case BGP_ATTR_MP_UNREACH_NLRI:
767 case BGP_ATTR_EXT_COMMUNITIES:
768 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000769 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000770 return BGP_ATTR_PARSE_ERROR;
771 }
772
773 /* Partial optional attributes that are malformed should not cause
774 * the whole session to be reset. Instead treat it as a withdrawal
775 * of the routes, if possible.
776 */
Paul Jakma835315b2012-01-18 12:28:30 +0000777 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
778 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
779 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000780 return BGP_ATTR_PARSE_WITHDRAW;
781
782 /* default to reset */
783 return BGP_ATTR_PARSE_ERROR;
784}
785
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400786/* Find out what is wrong with the path attribute flag bits and log the error.
787 "Flag bits" here stand for Optional, Transitive and Partial, but not for
788 Extended Length. Checking O/T/P bits at once implies, that the attribute
789 being diagnosed is defined by RFC as either a "well-known" or an "optional,
790 non-transitive" attribute. */
791static void
Paul Jakma835315b2012-01-18 12:28:30 +0000792bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
793 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400794)
795{
796 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000797 u_char real_flags = args->flags;
798 const u_int8_t attr_code = args->type;
799
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400800 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
801 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
802 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
803 if
804 (
805 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
806 CHECK_FLAG (real_flags, attr_flag_str[i].key)
807 )
808 {
Paul Jakma835315b2012-01-18 12:28:30 +0000809 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400810 LOOKUP (attr_str, attr_code),
811 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
812 attr_flag_str[i].str);
813 seen = 1;
814 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100815 if (!seen)
816 {
817 zlog (args->peer->log, LOG_DEBUG,
818 "Strange, %s called for attr %s, but no problem found with flags"
819 " (real flags 0x%x, desired 0x%x)",
820 __func__, LOOKUP (attr_str, attr_code),
821 real_flags, desired_flags);
822 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400823}
824
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000825/* Required flags for attributes. EXTLEN will be masked off when testing,
826 * as will PARTIAL for optional+transitive attributes.
827 */
828const u_int8_t attr_flags_values [] = {
829 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
830 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
831 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
832 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
833 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
834 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
835 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
836 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
837 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
838 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
839 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
840 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
841 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
842 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
843 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
844};
845static const size_t attr_flags_values_max =
846 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
847
848static int
Paul Jakma835315b2012-01-18 12:28:30 +0000849bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000850{
851 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000852 const u_int8_t flags = args->flags;
853 const u_int8_t attr_code = args->type;
854 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000855
856 /* there may be attributes we don't know about */
857 if (attr_code > attr_flags_values_max)
858 return 0;
859 if (attr_flags_values[attr_code] == 0)
860 return 0;
861
862 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
863 * 1."
864 */
865 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
866 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
867 {
868 zlog (peer->log, LOG_ERR,
869 "%s well-known attributes must have transitive flag set (%x)",
870 LOOKUP (attr_str, attr_code), flags);
871 return 1;
872 }
873
874 /* "For well-known attributes and for optional non-transitive attributes,
875 * the Partial bit MUST be set to 0."
876 */
877 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
878 {
879 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
880 {
881 zlog (peer->log, LOG_ERR,
882 "%s well-known attribute "
883 "must NOT have the partial flag set (%x)",
884 LOOKUP (attr_str, attr_code), flags);
885 return 1;
886 }
887 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
888 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
889 {
890 zlog (peer->log, LOG_ERR,
891 "%s optional + transitive attribute "
892 "must NOT have the partial flag set (%x)",
893 LOOKUP (attr_str, attr_code), flags);
894 return 1;
895 }
896 }
897
898 /* Optional transitive attributes may go through speakers that don't
899 * reocgnise them and set the Partial bit.
900 */
901 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
902 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
903 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
904
Paul Jakma683f2b82012-03-23 14:58:45 +0000905 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000906 == attr_flags_values[attr_code])
907 return 0;
908
Paul Jakma835315b2012-01-18 12:28:30 +0000909 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000910 return 1;
911}
912
paul718e3742002-12-13 20:15:29 +0000913/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000914static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000915bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000916{
Paul Jakma835315b2012-01-18 12:28:30 +0000917 struct peer *const peer = args->peer;
918 struct attr *const attr = args->attr;
919 const bgp_size_t length = args->length;
920
paul718e3742002-12-13 20:15:29 +0000921 /* If any recognized attribute has Attribute Length that conflicts
922 with the expected length (based on the attribute type code), then
923 the Error Subcode is set to Attribute Length Error. The Data
924 field contains the erroneous attribute (type, length and
925 value). */
926 if (length != 1)
927 {
928 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
929 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000930 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000931 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000932 args->total);
paul718e3742002-12-13 20:15:29 +0000933 }
934
935 /* Fetch origin attribute. */
936 attr->origin = stream_getc (BGP_INPUT (peer));
937
938 /* If the ORIGIN attribute has an undefined value, then the Error
939 Subcode is set to Invalid Origin Attribute. The Data field
940 contains the unrecognized attribute (type, length and value). */
941 if ((attr->origin != BGP_ORIGIN_IGP)
942 && (attr->origin != BGP_ORIGIN_EGP)
943 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
944 {
945 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
946 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000947 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000948 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000949 args->total);
paul718e3742002-12-13 20:15:29 +0000950 }
951
952 /* Set oring attribute flag. */
953 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
954
955 return 0;
956}
Paul Jakmaab005292010-11-27 22:48:34 +0000957
958/* Parse AS path information. This function is wrapper of
959 aspath_parse. */
960static int
Paul Jakma835315b2012-01-18 12:28:30 +0000961bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000962{
Paul Jakma835315b2012-01-18 12:28:30 +0000963 struct attr *const attr = args->attr;
964 struct peer *const peer = args->peer;
965 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000966
Paul Jakmaab005292010-11-27 22:48:34 +0000967 /*
968 * peer with AS4 => will get 4Byte ASnums
969 * otherwise, will get 16 Bit
970 */
971 attr->aspath = aspath_parse (peer->ibuf, length,
972 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
973
974 /* In case of IBGP, length will be zero. */
975 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000976 {
Paul Jakmab881c702010-11-23 16:35:42 +0000977 zlog (peer->log, LOG_ERR,
978 "Malformed AS path from %s, length is %d",
979 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000980 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000981 }
Chris Hallcddb8112010-08-09 22:31:37 +0400982
Paul Jakmaab005292010-11-27 22:48:34 +0000983 /* Set aspath attribute flag. */
984 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000985
Paul Jakmab881c702010-11-23 16:35:42 +0000986 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000987}
988
Paul Jakmab881c702010-11-23 16:35:42 +0000989static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000990bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000991{
992 /* These checks were part of bgp_attr_aspath, but with
993 * as4 we should to check aspath things when
994 * aspath synthesizing with as4_path has already taken place.
995 * Otherwise we check ASPATH and use the synthesized thing, and that is
996 * not right.
997 * So do the checks later, i.e. here
998 */
999 struct bgp *bgp = peer->bgp;
1000 struct aspath *aspath;
1001
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001002 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001003 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1004 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001005 {
1006 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001007 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1008 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1009 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001010 }
1011
paul718e3742002-12-13 20:15:29 +00001012 /* First AS check for EBGP. */
1013 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1014 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001015 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001016 && ! aspath_firstas_check (attr->aspath, peer->as))
1017 {
1018 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001019 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001020 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1021 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1022 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001023 }
1024 }
1025
1026 /* local-as prepend */
1027 if (peer->change_local_as &&
1028 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1029 {
1030 aspath = aspath_dup (attr->aspath);
1031 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001032 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001033 attr->aspath = aspath_intern (aspath);
1034 }
1035
Paul Jakmab881c702010-11-23 16:35:42 +00001036 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001037}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001038
Paul Jakmaab005292010-11-27 22:48:34 +00001039/* Parse AS4 path information. This function is another wrapper of
1040 aspath_parse. */
1041static int
Paul Jakma835315b2012-01-18 12:28:30 +00001042bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001043{
Paul Jakma835315b2012-01-18 12:28:30 +00001044 struct peer *const peer = args->peer;
1045 struct attr *const attr = args->attr;
1046 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001047
Paul Jakmaab005292010-11-27 22:48:34 +00001048 *as4_path = aspath_parse (peer->ibuf, length, 1);
1049
Paul Jakmab881c702010-11-23 16:35:42 +00001050 /* In case of IBGP, length will be zero. */
1051 if (!*as4_path)
1052 {
1053 zlog (peer->log, LOG_ERR,
1054 "Malformed AS4 path from %s, length is %d",
1055 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001056 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001057 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001058 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001059 }
1060
Paul Jakmaab005292010-11-27 22:48:34 +00001061 /* Set aspath attribute flag. */
1062 if (as4_path)
1063 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1064
Paul Jakmab881c702010-11-23 16:35:42 +00001065 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001066}
1067
paul718e3742002-12-13 20:15:29 +00001068/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001069static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001070bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001071{
Paul Jakma835315b2012-01-18 12:28:30 +00001072 struct peer *const peer = args->peer;
1073 struct attr *const attr = args->attr;
1074 const bgp_size_t length = args->length;
1075
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001076 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001077
paul718e3742002-12-13 20:15:29 +00001078 /* Check nexthop attribute length. */
1079 if (length != 4)
1080 {
1081 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1082 length);
1083
Paul Jakma835315b2012-01-18 12:28:30 +00001084 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001085 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001086 args->total);
paul718e3742002-12-13 20:15:29 +00001087 }
1088
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001089 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1090 attribute must result in a NOTIFICATION message (this is implemented below).
1091 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1092 logged locally (this is implemented somewhere else). The UPDATE message
1093 gets ignored in any of these cases. */
1094 nexthop_n = stream_get_ipv4 (peer->ibuf);
1095 nexthop_h = ntohl (nexthop_n);
1096 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1097 {
1098 char buf[INET_ADDRSTRLEN];
1099 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1100 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001101 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001102 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001103 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001104 }
1105
1106 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001107 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1108
Paul Jakmab881c702010-11-23 16:35:42 +00001109 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001110}
1111
1112/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001113static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001114bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001115{
Paul Jakma835315b2012-01-18 12:28:30 +00001116 struct peer *const peer = args->peer;
1117 struct attr *const attr = args->attr;
1118 const bgp_size_t length = args->length;
1119
paul718e3742002-12-13 20:15:29 +00001120 /* Length check. */
1121 if (length != 4)
1122 {
1123 zlog (peer->log, LOG_ERR,
1124 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001125
Paul Jakma835315b2012-01-18 12:28:30 +00001126 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001127 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001128 args->total);
paul718e3742002-12-13 20:15:29 +00001129 }
1130
1131 attr->med = stream_getl (peer->ibuf);
1132
1133 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1134
Paul Jakmab881c702010-11-23 16:35:42 +00001135 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001136}
1137
1138/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001139static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001140bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001141{
Paul Jakma835315b2012-01-18 12:28:30 +00001142 struct peer *const peer = args->peer;
1143 struct attr *const attr = args->attr;
1144 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001145
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001146 /* Length check. */
1147 if (length != 4)
1148 {
Paul Jakma835315b2012-01-18 12:28:30 +00001149 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1150 length);
1151 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001152 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001153 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001154 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001155
paul718e3742002-12-13 20:15:29 +00001156 /* If it is contained in an UPDATE message that is received from an
1157 external peer, then this attribute MUST be ignored by the
1158 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001159 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001160 {
paul9985f832005-02-09 15:51:56 +00001161 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001162 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001163 }
1164
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001165 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001166
1167 /* Set atomic aggregate flag. */
1168 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1169
Paul Jakmab881c702010-11-23 16:35:42 +00001170 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001171}
1172
1173/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001174static int
Paul Jakma835315b2012-01-18 12:28:30 +00001175bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001176{
Paul Jakma835315b2012-01-18 12:28:30 +00001177 struct peer *const peer = args->peer;
1178 struct attr *const attr = args->attr;
1179 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001180
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001181 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001182 if (length != 0)
1183 {
Paul Jakma835315b2012-01-18 12:28:30 +00001184 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1185 length);
1186 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001187 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001188 args->total);
paul718e3742002-12-13 20:15:29 +00001189 }
1190
1191 /* Set atomic aggregate flag. */
1192 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1193
Paul Jakmab881c702010-11-23 16:35:42 +00001194 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001195}
1196
1197/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001198static int
Paul Jakma835315b2012-01-18 12:28:30 +00001199bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001200{
Paul Jakma835315b2012-01-18 12:28:30 +00001201 struct peer *const peer = args->peer;
1202 struct attr *const attr = args->attr;
1203 const bgp_size_t length = args->length;
1204
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001206 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001207
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001208 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001209 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001210 wantedlen = 8;
1211
1212 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001213 {
Paul Jakma835315b2012-01-18 12:28:30 +00001214 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1215 wantedlen, length);
1216 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001217 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001218 args->total);
paul718e3742002-12-13 20:15:29 +00001219 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001220
1221 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1222 attre->aggregator_as = stream_getl (peer->ibuf);
1223 else
1224 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001225 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001226
1227 /* Set atomic aggregate flag. */
1228 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1229
Paul Jakmab881c702010-11-23 16:35:42 +00001230 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001231}
1232
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001233/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001234static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001235bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1236 as_t *as4_aggregator_as,
1237 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001238{
Paul Jakma835315b2012-01-18 12:28:30 +00001239 struct peer *const peer = args->peer;
1240 struct attr *const attr = args->attr;
1241 const bgp_size_t length = args->length;
1242
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001243 if (length != 8)
1244 {
Paul Jakma835315b2012-01-18 12:28:30 +00001245 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1246 length);
1247 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001248 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001249 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001250 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001251
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001252 *as4_aggregator_as = stream_getl (peer->ibuf);
1253 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1254
1255 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1256
Paul Jakmab881c702010-11-23 16:35:42 +00001257 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001258}
1259
1260/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1261 */
Paul Jakmab881c702010-11-23 16:35:42 +00001262static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001263bgp_attr_munge_as4_attrs (struct peer *const peer,
1264 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001265 struct aspath *as4_path, as_t as4_aggregator,
1266 struct in_addr *as4_aggregator_addr)
1267{
1268 int ignore_as4_path = 0;
1269 struct aspath *newpath;
1270 struct attr_extra *attre = attr->extra;
1271
Paul Jakmab881c702010-11-23 16:35:42 +00001272 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001273 {
1274 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1275 * if given.
1276 * It is worth a warning though, because the peer really
1277 * should not send them
1278 */
1279 if (BGP_DEBUG(as4, AS4))
1280 {
1281 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1282 zlog_debug ("[AS4] %s %s AS4_PATH",
1283 peer->host, "AS4 capable peer, yet it sent");
1284
1285 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1286 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1287 peer->host, "AS4 capable peer, yet it sent");
1288 }
1289
Paul Jakmab881c702010-11-23 16:35:42 +00001290 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001291 }
1292
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001293 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1294 * because that may override AS4_PATH
1295 */
1296 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1297 {
Paul Jakmab881c702010-11-23 16:35:42 +00001298 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001299 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001300 assert (attre);
1301
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001302 /* received both.
1303 * if the as_number in aggregator is not AS_TRANS,
1304 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1305 * and the Aggregator shall be taken as
1306 * info on the aggregating node, and the AS_PATH
1307 * shall be taken as the AS_PATH
1308 * otherwise
1309 * the Aggregator shall be ignored and the
1310 * AS4_AGGREGATOR shall be taken as the
1311 * Aggregating node and the AS_PATH is to be
1312 * constructed "as in all other cases"
1313 */
Paul Jakmab881c702010-11-23 16:35:42 +00001314 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001315 {
1316 /* ignore */
1317 if ( BGP_DEBUG(as4, AS4))
1318 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1319 " send AGGREGATOR != AS_TRANS and"
1320 " AS4_AGGREGATOR, so ignore"
1321 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1322 ignore_as4_path = 1;
1323 }
1324 else
1325 {
1326 /* "New_aggregator shall be taken as aggregator" */
1327 attre->aggregator_as = as4_aggregator;
1328 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1329 }
1330 }
1331 else
1332 {
1333 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1334 * That is bogus - but reading the conditions
1335 * we have to handle AS4_AGGREGATOR as if it were
1336 * AGGREGATOR in that case
1337 */
1338 if ( BGP_DEBUG(as4, AS4))
1339 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1340 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1341 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001342 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001343 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1344 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1345 }
1346 }
1347
1348 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001349 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001350 {
1351 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001352 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001353 attr->aspath = aspath_intern (newpath);
1354 }
Paul Jakmab881c702010-11-23 16:35:42 +00001355 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001356}
1357
paul718e3742002-12-13 20:15:29 +00001358/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001359static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001360bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001361{
Paul Jakma835315b2012-01-18 12:28:30 +00001362 struct peer *const peer = args->peer;
1363 struct attr *const attr = args->attr;
1364 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001365
paul718e3742002-12-13 20:15:29 +00001366 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001367 {
1368 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001369 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001370 }
Paul Jakma0c466382010-12-05 17:17:26 +00001371
1372 attr->community =
1373 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1374
1375 /* XXX: fix community_parse to use stream API and remove this */
1376 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001377
Paul Jakma0c466382010-12-05 17:17:26 +00001378 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001379 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001380 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001381 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001382
paul718e3742002-12-13 20:15:29 +00001383 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1384
Paul Jakmab881c702010-11-23 16:35:42 +00001385 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001386}
1387
1388/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001389static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001390bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001391{
Paul Jakma835315b2012-01-18 12:28:30 +00001392 struct peer *const peer = args->peer;
1393 struct attr *const attr = args->attr;
1394 const bgp_size_t length = args->length;
1395
Denis Ovsienkod595b562011-09-30 15:08:54 +04001396 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001397 if (length != 4)
1398 {
1399 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1400
Paul Jakma835315b2012-01-18 12:28:30 +00001401 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001402 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001403 args->total);
paul718e3742002-12-13 20:15:29 +00001404 }
1405
Paul Jakmafb982c22007-05-04 20:15:47 +00001406 (bgp_attr_extra_get (attr))->originator_id.s_addr
1407 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001408
1409 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1410
Paul Jakmab881c702010-11-23 16:35:42 +00001411 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001412}
1413
1414/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001415static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001416bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001417{
Paul Jakma835315b2012-01-18 12:28:30 +00001418 struct peer *const peer = args->peer;
1419 struct attr *const attr = args->attr;
1420 const bgp_size_t length = args->length;
1421
paul718e3742002-12-13 20:15:29 +00001422 /* Check length. */
1423 if (length % 4)
1424 {
1425 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1426
Paul Jakma835315b2012-01-18 12:28:30 +00001427 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1428 args->total);
paul718e3742002-12-13 20:15:29 +00001429 }
1430
Paul Jakmafb982c22007-05-04 20:15:47 +00001431 (bgp_attr_extra_get (attr))->cluster
1432 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001433
1434 /* XXX: Fix cluster_parse to use stream API and then remove this */
1435 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001436
1437 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1438
Paul Jakmab881c702010-11-23 16:35:42 +00001439 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001440}
1441
1442/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001443int
Paul Jakma835315b2012-01-18 12:28:30 +00001444bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1445 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001446{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001447 afi_t afi;
1448 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001449 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001450 size_t start;
paul718e3742002-12-13 20:15:29 +00001451 int ret;
1452 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001453 struct peer *const peer = args->peer;
1454 struct attr *const attr = args->attr;
1455 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001456 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001457
paul718e3742002-12-13 20:15:29 +00001458 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001459 s = BGP_INPUT(peer);
1460 start = stream_get_getp(s);
1461
1462 /* safe to read statically sized header? */
1463#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001464#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001465 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001466 {
1467 zlog_info ("%s: %s sent invalid length, %lu",
1468 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001469 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001470 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001471
paul718e3742002-12-13 20:15:29 +00001472 /* Load AFI, SAFI. */
1473 afi = stream_getw (s);
1474 safi = stream_getc (s);
1475
1476 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001477 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001478
Paul Jakma03292802008-06-07 20:37:10 +00001479 if (LEN_LEFT < attre->mp_nexthop_len)
1480 {
1481 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1482 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001483 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001484 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001485
paul718e3742002-12-13 20:15:29 +00001486 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001487 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001488 {
1489 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001490 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001491 /* Probably needed for RFC 2283 */
1492 if (attr->nexthop.s_addr == 0)
1493 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001494 break;
1495 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001496 stream_getl (s); /* RD high */
1497 stream_getl (s); /* RD low */
1498 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001499 break;
1500#ifdef HAVE_IPV6
1501 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001502 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001503 break;
1504 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001505 stream_get (&attre->mp_nexthop_global, s, 16);
1506 stream_get (&attre->mp_nexthop_local, s, 16);
1507 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001508 {
1509 char buf1[INET6_ADDRSTRLEN];
1510 char buf2[INET6_ADDRSTRLEN];
1511
1512 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001513 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 +00001514 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001515 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001516 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001517 buf2, INET6_ADDRSTRLEN));
1518
Paul Jakmafb982c22007-05-04 20:15:47 +00001519 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001520 }
1521 break;
1522#endif /* HAVE_IPV6 */
1523 default:
Paul Jakma03292802008-06-07 20:37:10 +00001524 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1525 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001526 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001527 }
1528
Paul Jakma03292802008-06-07 20:37:10 +00001529 if (!LEN_LEFT)
1530 {
1531 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1532 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001533 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001534 }
paul718e3742002-12-13 20:15:29 +00001535
Paul Jakma6e4ab122007-04-10 19:36:48 +00001536 {
1537 u_char val;
1538 if ((val = stream_getc (s)))
1539 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1540 peer->host, val);
1541 }
1542
1543 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001544 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001545 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001546 {
1547 zlog_info ("%s: (%s) Failed to read NLRI",
1548 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001549 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001550 }
paul718e3742002-12-13 20:15:29 +00001551
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001552 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001553 {
1554 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001555 if (ret < 0)
1556 {
1557 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1558 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001559 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001560 }
paul718e3742002-12-13 20:15:29 +00001561 }
1562
1563 mp_update->afi = afi;
1564 mp_update->safi = safi;
1565 mp_update->nlri = stream_pnt (s);
1566 mp_update->length = nlri_len;
1567
paul9985f832005-02-09 15:51:56 +00001568 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001569
Paul Jakmab881c702010-11-23 16:35:42 +00001570 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001571#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001572}
1573
1574/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001575int
Paul Jakma835315b2012-01-18 12:28:30 +00001576bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001577 struct bgp_nlri *mp_withdraw)
1578{
1579 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001580 afi_t afi;
1581 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001582 u_int16_t withdraw_len;
1583 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001584 struct peer *const peer = args->peer;
1585 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001586
1587 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001588
1589#define BGP_MP_UNREACH_MIN_SIZE 3
1590 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001591 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001592
paul718e3742002-12-13 20:15:29 +00001593 afi = stream_getw (s);
1594 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001595
1596 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001597
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001598 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001599 {
1600 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1601 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001602 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001603 }
1604
1605 mp_withdraw->afi = afi;
1606 mp_withdraw->safi = safi;
1607 mp_withdraw->nlri = stream_pnt (s);
1608 mp_withdraw->length = withdraw_len;
1609
paul9985f832005-02-09 15:51:56 +00001610 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001611
Paul Jakmab881c702010-11-23 16:35:42 +00001612 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001613}
1614
1615/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001616static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001617bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001618{
Paul Jakma835315b2012-01-18 12:28:30 +00001619 struct peer *const peer = args->peer;
1620 struct attr *const attr = args->attr;
1621 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001622
paul718e3742002-12-13 20:15:29 +00001623 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001624 {
1625 if (attr->extra)
1626 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001627 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001628 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001629 }
Paul Jakma0c466382010-12-05 17:17:26 +00001630
1631 (bgp_attr_extra_get (attr))->ecommunity =
1632 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1633 /* XXX: fix ecommunity_parse to use stream API */
1634 stream_forward_getp (peer->ibuf, length);
1635
1636 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001637 return bgp_attr_malformed (args,
1638 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1639 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001640
paul718e3742002-12-13 20:15:29 +00001641 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1642
Paul Jakmab881c702010-11-23 16:35:42 +00001643 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001644}
1645
1646/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001647static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001648bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001649{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001650 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001651 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001652 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001653 struct peer *const peer = args->peer;
1654 struct attr *const attr = args->attr;
1655 u_char *const startp = args->startp;
1656 const u_char type = args->type;
1657 const u_char flag = args->flags;
1658 const bgp_size_t length = args->length;
1659
paul718e3742002-12-13 20:15:29 +00001660
hassof4184462005-02-01 20:13:16 +00001661 if (BGP_DEBUG (normal, NORMAL))
1662 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1663 peer->host, type, length);
1664
paul718e3742002-12-13 20:15:29 +00001665 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001666 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001667 "Unknown attribute type %d length %d is received", type, length);
1668
1669 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001670 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001671
paul718e3742002-12-13 20:15:29 +00001672 /* If any of the mandatory well-known attributes are not recognized,
1673 then the Error Subcode is set to Unrecognized Well-known
1674 Attribute. The Data field contains the unrecognized attribute
1675 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001676 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001677 {
Paul Jakma835315b2012-01-18 12:28:30 +00001678 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001679 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001680 args->total);
paul718e3742002-12-13 20:15:29 +00001681 }
1682
1683 /* Unrecognized non-transitive optional attributes must be quietly
1684 ignored and not passed along to other BGP peers. */
1685 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001686 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001687
1688 /* If a path with recognized transitive optional attribute is
1689 accepted and passed along to other BGP peers and the Partial bit
1690 in the Attribute Flags octet is set to 1 by some previous AS, it
1691 is not set back to 0 by the current AS. */
1692 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1693
1694 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001695 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001696 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001697
Paul Jakmafb982c22007-05-04 20:15:47 +00001698 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001699
1700 if (transit->val)
1701 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1702 transit->length + total);
1703 else
1704 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1705
1706 memcpy (transit->val + transit->length, startp, total);
1707 transit->length += total;
1708
Paul Jakmab881c702010-11-23 16:35:42 +00001709 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001710}
1711
1712/* Read attribute of update packet. This function is called from
1713 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001714bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001715bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1716 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1717{
1718 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001719 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001720 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001721 bgp_size_t length;
1722 u_char *startp, *endp;
1723 u_char *attr_endp;
1724 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001725 /* we need the as4_path only until we have synthesized the as_path with it */
1726 /* same goes for as4_aggregator */
1727 struct aspath *as4_path = NULL;
1728 as_t as4_aggregator = 0;
1729 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001730
1731 /* Initialize bitmap. */
1732 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1733
1734 /* End pointer of BGP attribute. */
1735 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001736
paul718e3742002-12-13 20:15:29 +00001737 /* Get attributes to the end of attribute length. */
1738 while (BGP_INPUT_PNT (peer) < endp)
1739 {
1740 /* Check remaining length check.*/
1741 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1742 {
gdtc29fdba2004-12-09 14:46:46 +00001743 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001744 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001745 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001746 peer->host,
1747 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001748
1749 bgp_notify_send (peer,
1750 BGP_NOTIFY_UPDATE_ERR,
1751 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001752 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001753 }
1754
1755 /* Fetch attribute flag and type. */
1756 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001757 /* "The lower-order four bits of the Attribute Flags octet are
1758 unused. They MUST be zero when sent and MUST be ignored when
1759 received." */
1760 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001761 type = stream_getc (BGP_INPUT (peer));
1762
Paul Jakma370b64a2007-12-22 16:49:52 +00001763 /* Check whether Extended-Length applies and is in bounds */
1764 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1765 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1766 {
1767 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001768 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001769 peer->host,
1770 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1771
1772 bgp_notify_send (peer,
1773 BGP_NOTIFY_UPDATE_ERR,
1774 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001775 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001776 }
Paul Jakma835315b2012-01-18 12:28:30 +00001777
paul718e3742002-12-13 20:15:29 +00001778 /* Check extended attribue length bit. */
1779 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1780 length = stream_getw (BGP_INPUT (peer));
1781 else
1782 length = stream_getc (BGP_INPUT (peer));
1783
1784 /* If any attribute appears more than once in the UPDATE
1785 message, then the Error Subcode is set to Malformed Attribute
1786 List. */
1787
1788 if (CHECK_BITMAP (seen, type))
1789 {
1790 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001791 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001792 peer->host, type);
1793
1794 bgp_notify_send (peer,
1795 BGP_NOTIFY_UPDATE_ERR,
1796 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001797 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001798 }
1799
1800 /* Set type to bitmap to check duplicate attribute. `type' is
1801 unsigned char so it never overflow bitmap range. */
1802
1803 SET_BITMAP (seen, type);
1804
1805 /* Overflow check. */
1806 attr_endp = BGP_INPUT_PNT (peer) + length;
1807
1808 if (attr_endp > endp)
1809 {
1810 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001811 "%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 +00001812 bgp_notify_send (peer,
1813 BGP_NOTIFY_UPDATE_ERR,
1814 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001815 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001816 }
Paul Jakma835315b2012-01-18 12:28:30 +00001817
1818 struct bgp_attr_parser_args attr_args = {
1819 .peer = peer,
1820 .length = length,
1821 .attr = attr,
1822 .type = type,
1823 .flags = flag,
1824 .startp = startp,
1825 .total = attr_endp - startp,
1826 };
1827
1828
1829 /* If any recognized attribute has Attribute Flags that conflict
1830 with the Attribute Type Code, then the Error Subcode is set to
1831 Attribute Flags Error. The Data field contains the erroneous
1832 attribute (type, length and value). */
1833 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001834 {
1835 bgp_attr_parse_ret_t ret;
1836 ret = bgp_attr_malformed (&attr_args,
1837 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1838 attr_args.total);
1839 if (ret == BGP_ATTR_PARSE_PROCEED)
1840 continue;
1841 return ret;
1842 }
paul718e3742002-12-13 20:15:29 +00001843
1844 /* OK check attribute and store it's value. */
1845 switch (type)
1846 {
1847 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001848 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001849 break;
1850 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001851 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001852 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001853 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001854 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001855 break;
paul718e3742002-12-13 20:15:29 +00001856 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001857 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001858 break;
1859 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001860 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001861 break;
1862 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001863 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001864 break;
1865 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001866 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001867 break;
1868 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001869 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001870 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001871 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001872 ret = bgp_attr_as4_aggregator (&attr_args,
1873 &as4_aggregator,
1874 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001875 break;
paul718e3742002-12-13 20:15:29 +00001876 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001877 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001878 break;
1879 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001880 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001881 break;
1882 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001883 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001884 break;
1885 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001886 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001887 break;
1888 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001889 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001890 break;
1891 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001892 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001893 break;
1894 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001895 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001896 break;
1897 }
Paul Jakmab881c702010-11-23 16:35:42 +00001898
1899 /* If hard error occured immediately return to the caller. */
1900 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001901 {
1902 zlog (peer->log, LOG_WARNING,
1903 "%s: Attribute %s, parse error",
1904 peer->host,
1905 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001906 bgp_notify_send (peer,
1907 BGP_NOTIFY_UPDATE_ERR,
1908 BGP_NOTIFY_UPDATE_MAL_ATTR);
1909 if (as4_path)
1910 aspath_unintern (&as4_path);
1911 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001912 }
Paul Jakmab881c702010-11-23 16:35:42 +00001913 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1914 {
1915
1916 zlog (peer->log, LOG_WARNING,
1917 "%s: Attribute %s, parse error - treating as withdrawal",
1918 peer->host,
1919 LOOKUP (attr_str, type));
1920 if (as4_path)
1921 aspath_unintern (&as4_path);
1922 return ret;
1923 }
1924
paul718e3742002-12-13 20:15:29 +00001925 /* Check the fetched length. */
1926 if (BGP_INPUT_PNT (peer) != attr_endp)
1927 {
1928 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001929 "%s: BGP attribute %s, fetch error",
1930 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001931 bgp_notify_send (peer,
1932 BGP_NOTIFY_UPDATE_ERR,
1933 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001934 if (as4_path)
1935 aspath_unintern (&as4_path);
1936 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001937 }
1938 }
1939
1940 /* Check final read pointer is same as end pointer. */
1941 if (BGP_INPUT_PNT (peer) != endp)
1942 {
1943 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001944 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001945 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001946 bgp_notify_send (peer,
1947 BGP_NOTIFY_UPDATE_ERR,
1948 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001949 if (as4_path)
1950 aspath_unintern (&as4_path);
1951 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001952 }
1953
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001954 /*
1955 * At this place we can see whether we got AS4_PATH and/or
1956 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1957 * We can not do this before we've read all attributes because
1958 * the as4 handling does not say whether AS4_PATH has to be sent
1959 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1960 * in relationship to AGGREGATOR.
1961 * So, to be defensive, we are not relying on any order and read
1962 * all attributes first, including these 32bit ones, and now,
1963 * afterwards, we look what and if something is to be done for as4.
1964 */
Paul Jakma835315b2012-01-18 12:28:30 +00001965 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001966 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001967 {
1968 if (as4_path)
1969 aspath_unintern (&as4_path);
1970 return BGP_ATTR_PARSE_ERROR;
1971 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001972
1973 /* At this stage, we have done all fiddling with as4, and the
1974 * resulting info is in attr->aggregator resp. attr->aspath
1975 * so we can chuck as4_aggregator and as4_path alltogether in
1976 * order to save memory
1977 */
Paul Jakmab881c702010-11-23 16:35:42 +00001978 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001979 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001980 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001981 /* The flag that we got this is still there, but that does not
1982 * do any trouble
1983 */
1984 }
1985 /*
1986 * The "rest" of the code does nothing with as4_aggregator.
1987 * there is no memory attached specifically which is not part
1988 * of the attr.
1989 * so ignoring just means do nothing.
1990 */
1991 /*
1992 * Finally do the checks on the aspath we did not do yet
1993 * because we waited for a potentially synthesized aspath.
1994 */
Paul Jakmab881c702010-11-23 16:35:42 +00001995 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001996 {
Paul Jakma835315b2012-01-18 12:28:30 +00001997 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001998 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001999 return ret;
2000 }
2001
paul718e3742002-12-13 20:15:29 +00002002 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002003 if (attr->extra && attr->extra->transit)
2004 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002005
Paul Jakmab881c702010-11-23 16:35:42 +00002006 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002007}
2008
2009/* Well-known attribute check. */
2010int
2011bgp_attr_check (struct peer *peer, struct attr *attr)
2012{
2013 u_char type = 0;
2014
2015 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2016 type = BGP_ATTR_ORIGIN;
2017
2018 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2019 type = BGP_ATTR_AS_PATH;
2020
2021 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2022 type = BGP_ATTR_NEXT_HOP;
2023
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002024 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002025 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2026 type = BGP_ATTR_LOCAL_PREF;
2027
2028 if (type)
2029 {
2030 zlog (peer->log, LOG_WARNING,
2031 "%s Missing well-known attribute %d.",
2032 peer->host, type);
2033 bgp_notify_send_with_data (peer,
2034 BGP_NOTIFY_UPDATE_ERR,
2035 BGP_NOTIFY_UPDATE_MISS_ATTR,
2036 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002037 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002038 }
Paul Jakmab881c702010-11-23 16:35:42 +00002039 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002040}
2041
2042int stream_put_prefix (struct stream *, struct prefix *);
2043
2044/* Make attribute packet. */
2045bgp_size_t
2046bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2047 struct stream *s, struct attr *attr, struct prefix *p,
2048 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002049 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002050{
paulfe69a502005-09-10 16:55:02 +00002051 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002052 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002053 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002054 int send_as4_path = 0;
2055 int send_as4_aggregator = 0;
2056 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002057
2058 if (! bgp)
2059 bgp = bgp_get_default ();
2060
2061 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002062 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002063
2064 /* Origin attribute. */
2065 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2066 stream_putc (s, BGP_ATTR_ORIGIN);
2067 stream_putc (s, 1);
2068 stream_putc (s, attr->origin);
2069
2070 /* AS path attribute. */
2071
2072 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002073 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002074 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002075 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002076 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002077 {
2078 aspath = aspath_dup (attr->aspath);
2079
2080 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2081 {
2082 /* Strip the confed info, and then stuff our path CONFED_ID
2083 on the front */
2084 aspath = aspath_delete_confed_seq (aspath);
2085 aspath = aspath_add_seq (aspath, bgp->confed_id);
2086 }
2087 else
2088 {
2089 aspath = aspath_add_seq (aspath, peer->local_as);
2090 if (peer->change_local_as)
2091 aspath = aspath_add_seq (aspath, peer->change_local_as);
2092 }
2093 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002094 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002095 {
2096 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2097 aspath = aspath_dup (attr->aspath);
2098 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2099 }
2100 else
2101 aspath = attr->aspath;
2102
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002103 /* If peer is not AS4 capable, then:
2104 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2105 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2106 * types are in it (i.e. exclude them if they are there)
2107 * AND do this only if there is at least one asnum > 65535 in the path!
2108 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2109 * all ASnums > 65535 to BGP_AS_TRANS
2110 */
paul718e3742002-12-13 20:15:29 +00002111
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002112 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2113 stream_putc (s, BGP_ATTR_AS_PATH);
2114 aspath_sizep = stream_get_endp (s);
2115 stream_putw (s, 0);
2116 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2117
2118 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2119 * in the path
2120 */
2121 if (!use32bit && aspath_has_as4 (aspath))
2122 send_as4_path = 1; /* we'll do this later, at the correct place */
2123
paul718e3742002-12-13 20:15:29 +00002124 /* Nexthop attribute. */
2125 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2126 {
2127 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2128 stream_putc (s, BGP_ATTR_NEXT_HOP);
2129 stream_putc (s, 4);
2130 if (safi == SAFI_MPLS_VPN)
2131 {
2132 if (attr->nexthop.s_addr == 0)
2133 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2134 else
2135 stream_put_ipv4 (s, attr->nexthop.s_addr);
2136 }
2137 else
2138 stream_put_ipv4 (s, attr->nexthop.s_addr);
2139 }
2140
2141 /* MED attribute. */
2142 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2143 {
2144 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2145 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2146 stream_putc (s, 4);
2147 stream_putl (s, attr->med);
2148 }
2149
2150 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002151 if (peer->sort == BGP_PEER_IBGP ||
2152 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002153 {
2154 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2155 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2156 stream_putc (s, 4);
2157 stream_putl (s, attr->local_pref);
2158 }
2159
2160 /* Atomic aggregate. */
2161 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2162 {
2163 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2164 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2165 stream_putc (s, 0);
2166 }
2167
2168 /* Aggregator. */
2169 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2170 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002171 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002172
2173 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002174 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2175 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002176
2177 if (use32bit)
2178 {
2179 /* AS4 capable peer */
2180 stream_putc (s, 8);
2181 stream_putl (s, attr->extra->aggregator_as);
2182 }
2183 else
2184 {
2185 /* 2-byte AS peer */
2186 stream_putc (s, 6);
2187
2188 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2189 if ( attr->extra->aggregator_as > 65535 )
2190 {
2191 stream_putw (s, BGP_AS_TRANS);
2192
2193 /* we have to send AS4_AGGREGATOR, too.
2194 * we'll do that later in order to send attributes in ascending
2195 * order.
2196 */
2197 send_as4_aggregator = 1;
2198 }
2199 else
2200 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2201 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002202 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002203 }
2204
2205 /* Community attribute. */
2206 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2207 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2208 {
2209 if (attr->community->size * 4 > 255)
2210 {
2211 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2212 stream_putc (s, BGP_ATTR_COMMUNITIES);
2213 stream_putw (s, attr->community->size * 4);
2214 }
2215 else
2216 {
2217 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2218 stream_putc (s, BGP_ATTR_COMMUNITIES);
2219 stream_putc (s, attr->community->size * 4);
2220 }
2221 stream_put (s, attr->community->val, attr->community->size * 4);
2222 }
2223
2224 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002225 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002226 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002227 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002228 {
2229 /* Originator ID. */
2230 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2231 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2232 stream_putc (s, 4);
2233
2234 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002235 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002236 else
2237 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002238
2239 /* Cluster list. */
2240 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2241 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2242
Paul Jakma9eda90c2007-08-30 13:36:17 +00002243 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002244 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002245 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002246 /* If this peer configuration's parent BGP has cluster_id. */
2247 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2248 stream_put_in_addr (s, &bgp->cluster_id);
2249 else
2250 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002251 stream_put (s, attr->extra->cluster->list,
2252 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002253 }
2254 else
2255 {
2256 stream_putc (s, 4);
2257 /* If this peer configuration's parent BGP has cluster_id. */
2258 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2259 stream_put_in_addr (s, &bgp->cluster_id);
2260 else
2261 stream_put_in_addr (s, &bgp->router_id);
2262 }
2263 }
2264
2265#ifdef HAVE_IPV6
2266 /* If p is IPv6 address put it into attribute. */
2267 if (p->family == AF_INET6)
2268 {
2269 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002270 struct attr_extra *attre = attr->extra;
2271
2272 assert (attr->extra);
2273
paul718e3742002-12-13 20:15:29 +00002274 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2275 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002276 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002277 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002278 stream_putw (s, AFI_IP6); /* AFI */
2279 stream_putc (s, safi); /* SAFI */
2280
Paul Jakmafb982c22007-05-04 20:15:47 +00002281 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002282
Paul Jakmafb982c22007-05-04 20:15:47 +00002283 if (attre->mp_nexthop_len == 16)
2284 stream_put (s, &attre->mp_nexthop_global, 16);
2285 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002286 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002287 stream_put (s, &attre->mp_nexthop_global, 16);
2288 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002289 }
2290
2291 /* SNPA */
2292 stream_putc (s, 0);
2293
paul718e3742002-12-13 20:15:29 +00002294 /* Prefix write. */
2295 stream_put_prefix (s, p);
2296
2297 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002298 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002299 }
2300#endif /* HAVE_IPV6 */
2301
2302 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2303 {
2304 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002305
2306 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2307 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002308 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002309 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002310 stream_putw (s, AFI_IP); /* AFI */
2311 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2312
2313 stream_putc (s, 4);
2314 stream_put_ipv4 (s, attr->nexthop.s_addr);
2315
2316 /* SNPA */
2317 stream_putc (s, 0);
2318
paul718e3742002-12-13 20:15:29 +00002319 /* Prefix write. */
2320 stream_put_prefix (s, p);
2321
2322 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002323 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002324 }
2325
2326 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2327 {
2328 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002329
2330 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2331 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002332 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002333 stream_putc (s, 0); /* Length of this attribute. */
2334 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002335 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002336
2337 stream_putc (s, 12);
2338 stream_putl (s, 0);
2339 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002340 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002341
2342 /* SNPA */
2343 stream_putc (s, 0);
2344
paul718e3742002-12-13 20:15:29 +00002345 /* Tag, RD, Prefix write. */
2346 stream_putc (s, p->prefixlen + 88);
2347 stream_put (s, tag, 3);
2348 stream_put (s, prd->val, 8);
2349 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2350
2351 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002352 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002353 }
2354
2355 /* Extended Communities attribute. */
2356 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2357 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2358 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002359 struct attr_extra *attre = attr->extra;
2360
2361 assert (attre);
2362
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002363 if (peer->sort == BGP_PEER_IBGP
2364 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002365 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002366 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002367 {
2368 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2369 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002370 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002371 }
2372 else
2373 {
2374 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2375 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002376 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002377 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002378 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002379 }
2380 else
2381 {
paul5228ad22004-06-04 17:58:18 +00002382 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002383 int tbit;
2384 int ecom_tr_size = 0;
2385 int i;
2386
Paul Jakmafb982c22007-05-04 20:15:47 +00002387 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002388 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002389 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002390 tbit = *pnt;
2391
2392 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2393 continue;
2394
2395 ecom_tr_size++;
2396 }
2397
2398 if (ecom_tr_size)
2399 {
2400 if (ecom_tr_size * 8 > 255)
2401 {
2402 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2403 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2404 stream_putw (s, ecom_tr_size * 8);
2405 }
2406 else
2407 {
2408 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2409 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2410 stream_putc (s, ecom_tr_size * 8);
2411 }
2412
Paul Jakmafb982c22007-05-04 20:15:47 +00002413 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002414 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002415 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002416 tbit = *pnt;
2417
2418 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2419 continue;
2420
2421 stream_put (s, pnt, 8);
2422 }
2423 }
paul718e3742002-12-13 20:15:29 +00002424 }
paul718e3742002-12-13 20:15:29 +00002425 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002426
2427 if ( send_as4_path )
2428 {
2429 /* If the peer is NOT As4 capable, AND */
2430 /* there are ASnums > 65535 in path THEN
2431 * give out AS4_PATH */
2432
2433 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2434 * path segments!
2435 * Hm, I wonder... confederation things *should* only be at
2436 * the beginning of an aspath, right? Then we should use
2437 * aspath_delete_confed_seq for this, because it is already
2438 * there! (JK)
2439 * Folks, talk to me: what is reasonable here!?
2440 */
2441 aspath = aspath_delete_confed_seq (aspath);
2442
2443 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2444 stream_putc (s, BGP_ATTR_AS4_PATH);
2445 aspath_sizep = stream_get_endp (s);
2446 stream_putw (s, 0);
2447 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2448 }
2449
2450 if (aspath != attr->aspath)
2451 aspath_free (aspath);
2452
2453 if ( send_as4_aggregator )
2454 {
2455 assert (attr->extra);
2456
2457 /* send AS4_AGGREGATOR, at this place */
2458 /* this section of code moved here in order to ensure the correct
2459 * *ascending* order of attributes
2460 */
2461 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2462 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2463 stream_putc (s, 8);
2464 stream_putl (s, attr->extra->aggregator_as);
2465 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2466 }
Paul Jakma41367172007-08-06 15:24:51 +00002467
paul718e3742002-12-13 20:15:29 +00002468 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002469 if (attr->extra && attr->extra->transit)
2470 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002471
2472 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002473 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002474}
2475
2476bgp_size_t
2477bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2478 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002479 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002480{
2481 unsigned long cp;
2482 unsigned long attrlen_pnt;
2483 bgp_size_t size;
2484
paul9985f832005-02-09 15:51:56 +00002485 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002486
2487 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2488 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2489
paul9985f832005-02-09 15:51:56 +00002490 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002491 stream_putc (s, 0); /* Length of this attribute. */
2492
2493 stream_putw (s, family2afi (p->family));
2494
2495 if (safi == SAFI_MPLS_VPN)
2496 {
2497 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002498 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002499
2500 /* prefix. */
2501 stream_putc (s, p->prefixlen + 88);
2502 stream_put (s, tag, 3);
2503 stream_put (s, prd->val, 8);
2504 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2505 }
2506 else
2507 {
2508 /* SAFI */
2509 stream_putc (s, safi);
2510
2511 /* prefix */
2512 stream_put_prefix (s, p);
2513 }
2514
2515 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002516 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002517 stream_putc_at (s, attrlen_pnt, size);
2518
paul9985f832005-02-09 15:51:56 +00002519 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002520}
2521
2522/* Initialization of attribute. */
2523void
paulfe69a502005-09-10 16:55:02 +00002524bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002525{
paul718e3742002-12-13 20:15:29 +00002526 aspath_init ();
2527 attrhash_init ();
2528 community_init ();
2529 ecommunity_init ();
2530 cluster_init ();
2531 transit_init ();
2532}
2533
Chris Caputo228da422009-07-18 05:44:03 +00002534void
2535bgp_attr_finish (void)
2536{
2537 aspath_finish ();
2538 attrhash_finish ();
2539 community_finish ();
2540 ecommunity_finish ();
2541 cluster_finish ();
2542 transit_finish ();
2543}
2544
paul718e3742002-12-13 20:15:29 +00002545/* Make attribute packet. */
2546void
paula3845922003-10-18 01:30:50 +00002547bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2548 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002549{
2550 unsigned long cp;
2551 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002552 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002553 struct aspath *aspath;
2554
2555 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002556 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002557
2558 /* Place holder of length. */
2559 stream_putw (s, 0);
2560
2561 /* Origin attribute. */
2562 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2563 stream_putc (s, BGP_ATTR_ORIGIN);
2564 stream_putc (s, 1);
2565 stream_putc (s, attr->origin);
2566
2567 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002568
2569 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2570 stream_putc (s, BGP_ATTR_AS_PATH);
2571 aspath_lenp = stream_get_endp (s);
2572 stream_putw (s, 0);
2573
2574 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002575
2576 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002577 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2578 if(prefix != NULL
2579#ifdef HAVE_IPV6
2580 && prefix->family != AF_INET6
2581#endif /* HAVE_IPV6 */
2582 )
2583 {
2584 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2585 stream_putc (s, BGP_ATTR_NEXT_HOP);
2586 stream_putc (s, 4);
2587 stream_put_ipv4 (s, attr->nexthop.s_addr);
2588 }
paul718e3742002-12-13 20:15:29 +00002589
2590 /* MED attribute. */
2591 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2592 {
2593 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2594 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2595 stream_putc (s, 4);
2596 stream_putl (s, attr->med);
2597 }
2598
2599 /* Local preference. */
2600 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2601 {
2602 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2603 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2604 stream_putc (s, 4);
2605 stream_putl (s, attr->local_pref);
2606 }
2607
2608 /* Atomic aggregate. */
2609 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2610 {
2611 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2612 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2613 stream_putc (s, 0);
2614 }
2615
2616 /* Aggregator. */
2617 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2618 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002619 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002620 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2621 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002622 stream_putc (s, 8);
2623 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002624 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002625 }
2626
2627 /* Community attribute. */
2628 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2629 {
2630 if (attr->community->size * 4 > 255)
2631 {
2632 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2633 stream_putc (s, BGP_ATTR_COMMUNITIES);
2634 stream_putw (s, attr->community->size * 4);
2635 }
2636 else
2637 {
2638 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2639 stream_putc (s, BGP_ATTR_COMMUNITIES);
2640 stream_putc (s, attr->community->size * 4);
2641 }
2642 stream_put (s, attr->community->val, attr->community->size * 4);
2643 }
2644
paula3845922003-10-18 01:30:50 +00002645#ifdef HAVE_IPV6
2646 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002647 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2648 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002649 {
2650 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002651 struct attr_extra *attre = attr->extra;
2652
paula3845922003-10-18 01:30:50 +00002653 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2654 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002655 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002656
2657 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002658 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002659 stream_putw(s, AFI_IP6); /* AFI */
2660 stream_putc(s, SAFI_UNICAST); /* SAFI */
2661
2662 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002663 stream_putc(s, attre->mp_nexthop_len);
2664 stream_put(s, &attre->mp_nexthop_global, 16);
2665 if (attre->mp_nexthop_len == 32)
2666 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002667
2668 /* SNPA */
2669 stream_putc(s, 0);
2670
2671 /* Prefix */
2672 stream_put_prefix(s, prefix);
2673
2674 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002675 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002676 }
2677#endif /* HAVE_IPV6 */
2678
paul718e3742002-12-13 20:15:29 +00002679 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002680 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002681 stream_putw_at (s, cp, len);
2682}