blob: 1dce39bcc3321f60df4deec344a1c130915bcf2a [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};
Balaji.G837d16c2012-09-26 14:09:10 +053065static const int attr_str_max = array_size(attr_str);
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};
Balaji.G837d16c2012-09-26 14:09:10 +053075static const size_t attr_flag_str_max = array_size(attr_flag_str);
paul718e3742002-12-13 20:15:29 +000076
Stephen Hemminger9bddac42009-05-15 09:59:51 -070077static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000078
paul94f2b392005-06-28 12:44:16 +000079static void *
Paul Jakma923de652007-04-29 18:25:17 +000080cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000081{
Paul Jakma923de652007-04-29 18:25:17 +000082 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000083 struct cluster_list *cluster;
84
85 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
86 cluster->length = val->length;
87
88 if (cluster->length)
89 {
90 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
91 memcpy (cluster->list, val->list, val->length);
92 }
93 else
94 cluster->list = NULL;
95
96 cluster->refcnt = 0;
97
98 return cluster;
99}
100
101/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +0000102static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +0000103cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +0000104{
105 struct cluster_list tmp;
106 struct cluster_list *cluster;
107
108 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +0000109 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000110
111 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
112 cluster->refcnt++;
113 return cluster;
114}
115
116int
117cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
118{
119 int i;
120
121 for (i = 0; i < cluster->length / 4; i++)
122 if (cluster->list[i].s_addr == originator.s_addr)
123 return 1;
124 return 0;
125}
126
paul94f2b392005-06-28 12:44:16 +0000127static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000128cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000129{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700130 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000131
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700132 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000133}
134
paul94f2b392005-06-28 12:44:16 +0000135static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000137{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100138 const struct cluster_list * cluster1 = p1;
139 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000140
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100141 return (cluster1->length == cluster2->length &&
142 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000143}
144
paul94f2b392005-06-28 12:44:16 +0000145static void
paul718e3742002-12-13 20:15:29 +0000146cluster_free (struct cluster_list *cluster)
147{
148 if (cluster->list)
149 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
150 XFREE (MTYPE_CLUSTER, cluster);
151}
152
Chris Caputo228da422009-07-18 05:44:03 +0000153#if 0
paul94f2b392005-06-28 12:44:16 +0000154static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000155cluster_dup (struct cluster_list *cluster)
156{
157 struct cluster_list *new;
158
Stephen Hemminger393deb92008-08-18 14:13:29 -0700159 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000160 new->length = cluster->length;
161
162 if (cluster->length)
163 {
164 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
165 memcpy (new->list, cluster->list, cluster->length);
166 }
167 else
168 new->list = NULL;
169
170 return new;
171}
Chris Caputo228da422009-07-18 05:44:03 +0000172#endif
paul718e3742002-12-13 20:15:29 +0000173
paul94f2b392005-06-28 12:44:16 +0000174static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000175cluster_intern (struct cluster_list *cluster)
176{
177 struct cluster_list *find;
178
179 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
180 find->refcnt++;
181
182 return find;
183}
184
185void
186cluster_unintern (struct cluster_list *cluster)
187{
paul718e3742002-12-13 20:15:29 +0000188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400193 hash_release (cluster_hash, cluster);
paul718e3742002-12-13 20:15:29 +0000194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
paul718e3742002-12-13 20:15:29 +0000246 if (transit->refcnt)
247 transit->refcnt--;
248
249 if (transit->refcnt == 0)
250 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400251 hash_release (transit_hash, transit);
paul718e3742002-12-13 20:15:29 +0000252 transit_free (transit);
253 }
254}
255
paul94f2b392005-06-28 12:44:16 +0000256static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000257transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000258{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700259 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000260
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700261 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000262}
263
paul94f2b392005-06-28 12:44:16 +0000264static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100265transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000266{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100267 const struct transit * transit1 = p1;
268 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000269
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100270 return (transit1->length == transit2->length &&
271 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000272}
273
paul94f2b392005-06-28 12:44:16 +0000274static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800275transit_init (void)
paul718e3742002-12-13 20:15:29 +0000276{
277 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
278}
Chris Caputo228da422009-07-18 05:44:03 +0000279
280static void
281transit_finish (void)
282{
283 hash_free (transit_hash);
284 transit_hash = NULL;
285}
paul718e3742002-12-13 20:15:29 +0000286
287/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700288static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000289
Paul Jakmafb982c22007-05-04 20:15:47 +0000290static struct attr_extra *
291bgp_attr_extra_new (void)
292{
293 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
294}
295
296void
297bgp_attr_extra_free (struct attr *attr)
298{
299 if (attr->extra)
300 {
301 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
302 attr->extra = NULL;
303 }
304}
305
306struct attr_extra *
307bgp_attr_extra_get (struct attr *attr)
308{
309 if (!attr->extra)
310 attr->extra = bgp_attr_extra_new();
311 return attr->extra;
312}
313
314/* Shallow copy of an attribute
315 * Though, not so shallow that it doesn't copy the contents
316 * of the attr_extra pointed to by 'extra'
317 */
318void
319bgp_attr_dup (struct attr *new, struct attr *orig)
320{
Jorge Boncompte [DTI2]558d1fe2012-05-07 16:53:05 +0000321 struct attr_extra *extra = new->extra;
322
Paul Jakmafb982c22007-05-04 20:15:47 +0000323 *new = *orig;
Christian Frankea0de1d12012-12-07 16:35:00 +0000324 /* if caller provided attr_extra space, use it in any case.
325 *
326 * This is neccesary even if orig->extra equals NULL, because otherwise
327 * memory may be later allocated on the heap by bgp_attr_extra_get.
328 *
329 * That memory would eventually be leaked, because the caller must not
330 * call bgp_attr_extra_free if he provided attr_extra on the stack.
331 */
332 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000333 {
Christian Frankea0de1d12012-12-07 16:35:00 +0000334 new->extra = extra;
335 memset(new->extra, 0, sizeof(struct attr_extra));
336 if (orig->extra)
337 *new->extra = *orig->extra;
338 }
339 else if (orig->extra)
340 {
341 new->extra = bgp_attr_extra_new();
Paul Jakmafb982c22007-05-04 20:15:47 +0000342 *new->extra = *orig->extra;
343 }
344}
345
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000346unsigned long int
347attr_count (void)
348{
349 return attrhash->count;
350}
351
352unsigned long int
353attr_unknown_count (void)
354{
355 return transit_hash->count;
356}
357
paul718e3742002-12-13 20:15:29 +0000358unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000359attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000360{
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000361 const struct attr *attr = (struct attr *) p;
362 const struct attr_extra *extra = attr->extra;
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700363 uint32_t key = 0;
364#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000365
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700366 MIX(attr->origin);
367 MIX(attr->nexthop.s_addr);
368 MIX(attr->med);
369 MIX(attr->local_pref);
370
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000371 key += attr->origin;
372 key += attr->nexthop.s_addr;
373 key += attr->med;
374 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000375
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000376 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000377 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000378 MIX(extra->aggregator_as);
379 MIX(extra->aggregator_addr.s_addr);
380 MIX(extra->weight);
381 MIX(extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000382 }
383
paul718e3742002-12-13 20:15:29 +0000384 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700385 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000386 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700387 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000388
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000389 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000390 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000391 if (extra->ecommunity)
392 MIX(ecommunity_hash_make (extra->ecommunity));
393 if (extra->cluster)
394 MIX(cluster_hash_key_make (extra->cluster));
395 if (extra->transit)
396 MIX(transit_hash_key_make (extra->transit));
paul718e3742002-12-13 20:15:29 +0000397
398#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000399 MIX(extra->mp_nexthop_len);
400 key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
401 key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000402#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000403 }
paul718e3742002-12-13 20:15:29 +0000404
405 return key;
406}
407
408int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100409attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000410{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100411 const struct attr * attr1 = p1;
412 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000413
paul718e3742002-12-13 20:15:29 +0000414 if (attr1->flag == attr2->flag
415 && attr1->origin == attr2->origin
416 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000417 && attr1->aspath == attr2->aspath
418 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000419 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000420 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000421 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100422 const struct attr_extra *ae1 = attr1->extra;
423 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000424
425 if (ae1 && ae2
426 && ae1->aggregator_as == ae2->aggregator_as
427 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
428 && ae1->weight == ae2->weight
429#ifdef HAVE_IPV6
430 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
431 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
432 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
433#endif /* HAVE_IPV6 */
434 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
435 && ae1->ecommunity == ae2->ecommunity
436 && ae1->cluster == ae2->cluster
437 && ae1->transit == ae2->transit)
438 return 1;
439 else if (ae1 || ae2)
440 return 0;
441 /* neither attribute has extra attributes, so they're same */
442 return 1;
443 }
paul718e3742002-12-13 20:15:29 +0000444 else
445 return 0;
446}
447
paul94f2b392005-06-28 12:44:16 +0000448static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100449attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000450{
451 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
452}
453
paul94f2b392005-06-28 12:44:16 +0000454static void
Chris Caputo228da422009-07-18 05:44:03 +0000455attrhash_finish (void)
456{
457 hash_free (attrhash);
458 attrhash = NULL;
459}
460
461static void
paul718e3742002-12-13 20:15:29 +0000462attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
463{
464 struct attr *attr = backet->data;
465
466 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
467 inet_ntoa (attr->nexthop), VTY_NEWLINE);
468}
469
470void
471attr_show_all (struct vty *vty)
472{
473 hash_iterate (attrhash,
474 (void (*)(struct hash_backet *, void *))
475 attr_show_all_iterator,
476 vty);
477}
478
paul94f2b392005-06-28 12:44:16 +0000479static void *
Paul Jakma923de652007-04-29 18:25:17 +0000480bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000481{
Paul Jakma923de652007-04-29 18:25:17 +0000482 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000483 struct attr *attr;
484
485 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
486 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000487 if (val->extra)
488 {
489 attr->extra = bgp_attr_extra_new ();
490 *attr->extra = *val->extra;
491 }
paul718e3742002-12-13 20:15:29 +0000492 attr->refcnt = 0;
493 return attr;
494}
495
496/* Internet argument attribute. */
497struct attr *
498bgp_attr_intern (struct attr *attr)
499{
500 struct attr *find;
501
502 /* Intern referenced strucutre. */
503 if (attr->aspath)
504 {
505 if (! attr->aspath->refcnt)
506 attr->aspath = aspath_intern (attr->aspath);
507 else
508 attr->aspath->refcnt++;
509 }
510 if (attr->community)
511 {
512 if (! attr->community->refcnt)
513 attr->community = community_intern (attr->community);
514 else
515 attr->community->refcnt++;
516 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000517 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000518 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000519 struct attr_extra *attre = attr->extra;
520
521 if (attre->ecommunity)
522 {
523 if (! attre->ecommunity->refcnt)
524 attre->ecommunity = ecommunity_intern (attre->ecommunity);
525 else
526 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000527
Paul Jakmafb982c22007-05-04 20:15:47 +0000528 }
529 if (attre->cluster)
530 {
531 if (! attre->cluster->refcnt)
532 attre->cluster = cluster_intern (attre->cluster);
533 else
534 attre->cluster->refcnt++;
535 }
536 if (attre->transit)
537 {
538 if (! attre->transit->refcnt)
539 attre->transit = transit_intern (attre->transit);
540 else
541 attre->transit->refcnt++;
542 }
paul718e3742002-12-13 20:15:29 +0000543 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000544
paul718e3742002-12-13 20:15:29 +0000545 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
546 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000547
paul718e3742002-12-13 20:15:29 +0000548 return find;
549}
550
Paul Jakma03e214c2007-04-29 18:31:07 +0000551
paul718e3742002-12-13 20:15:29 +0000552/* Make network statement's attribute. */
553struct attr *
554bgp_attr_default_set (struct attr *attr, u_char origin)
555{
556 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000557 bgp_attr_extra_get (attr);
558
paul718e3742002-12-13 20:15:29 +0000559 attr->origin = origin;
560 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
561 attr->aspath = aspath_empty ();
562 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000563 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000564 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
565#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000566 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000567#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000568
paul718e3742002-12-13 20:15:29 +0000569 return attr;
570}
571
Paul Jakma03e214c2007-04-29 18:31:07 +0000572
paul718e3742002-12-13 20:15:29 +0000573/* Make network statement's attribute. */
574struct attr *
575bgp_attr_default_intern (u_char origin)
576{
577 struct attr attr;
578 struct attr *new;
Jorge Boncompte [DTI2]e16a4132012-05-07 16:52:57 +0000579
Paul Jakma03e214c2007-04-29 18:31:07 +0000580 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000581
582 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000583 bgp_attr_extra_free (&attr);
584
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000585 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000586 return new;
587}
588
589struct attr *
590bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
591 struct aspath *aspath,
592 struct community *community, int as_set)
593{
594 struct attr attr;
595 struct attr *new;
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000596 struct attr_extra attre;
paul718e3742002-12-13 20:15:29 +0000597
598 memset (&attr, 0, sizeof (struct attr));
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000599 memset (&attre, 0, sizeof (struct attr_extra));
600 attr.extra = &attre;
601
paul718e3742002-12-13 20:15:29 +0000602 /* Origin attribute. */
603 attr.origin = origin;
604 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
605
606 /* AS path attribute. */
607 if (aspath)
608 attr.aspath = aspath_intern (aspath);
609 else
610 attr.aspath = aspath_empty ();
611 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
612
613 /* Next hop attribute. */
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
615
616 if (community)
617 {
618 attr.community = community;
619 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
620 }
621
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000622 attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000623#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000624 attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000625#endif
626 if (! as_set)
627 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
628 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
629 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000630 attre.aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000631 else
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000632 attre.aggregator_as = bgp->as;
633 attre.aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000634
635 new = bgp_attr_intern (&attr);
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000636
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000637 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000638 return new;
639}
640
Paul Jakmab881c702010-11-23 16:35:42 +0000641/* Unintern just the sub-components of the attr, but not the attr */
642void
643bgp_attr_unintern_sub (struct attr *attr)
644{
645 /* aspath refcount shoud be decrement. */
646 if (attr->aspath)
647 aspath_unintern (&attr->aspath);
648 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
649
650 if (attr->community)
651 community_unintern (&attr->community);
652 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
653
654 if (attr->extra)
655 {
656 if (attr->extra->ecommunity)
657 ecommunity_unintern (&attr->extra->ecommunity);
658 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
659
660 if (attr->extra->cluster)
661 cluster_unintern (attr->extra->cluster);
662 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
663
664 if (attr->extra->transit)
665 transit_unintern (attr->extra->transit);
666 }
667}
668
paul718e3742002-12-13 20:15:29 +0000669/* Free bgp attribute and aspath. */
670void
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000671bgp_attr_unintern (struct attr **pattr)
paul718e3742002-12-13 20:15:29 +0000672{
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000673 struct attr *attr = *pattr;
paul718e3742002-12-13 20:15:29 +0000674 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000675 struct attr tmp;
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000676 struct attr_extra tmp_extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000677
paul718e3742002-12-13 20:15:29 +0000678 /* Decrement attribute reference. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000679 attr->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000680
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000681 tmp = *attr;
Paul Jakmab881c702010-11-23 16:35:42 +0000682
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000683 if (attr->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000684 {
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000685 tmp.extra = &tmp_extra;
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000686 memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000687 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000688
paul718e3742002-12-13 20:15:29 +0000689 /* If reference becomes zero then free attribute object. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000690 if (attr->refcnt == 0)
691 {
692 ret = hash_release (attrhash, attr);
paul718e3742002-12-13 20:15:29 +0000693 assert (ret != NULL);
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000694 bgp_attr_extra_free (attr);
695 XFREE (MTYPE_ATTR, attr);
696 *pattr = NULL;
paul718e3742002-12-13 20:15:29 +0000697 }
698
Paul Jakmab881c702010-11-23 16:35:42 +0000699 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000700}
701
702void
703bgp_attr_flush (struct attr *attr)
704{
705 if (attr->aspath && ! attr->aspath->refcnt)
706 aspath_free (attr->aspath);
707 if (attr->community && ! attr->community->refcnt)
708 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000709 if (attr->extra)
710 {
711 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000712
Paul Jakmafb982c22007-05-04 20:15:47 +0000713 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000714 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000715 if (attre->cluster && ! attre->cluster->refcnt)
716 cluster_free (attre->cluster);
717 if (attre->transit && ! attre->transit->refcnt)
718 transit_free (attre->transit);
719 }
paul718e3742002-12-13 20:15:29 +0000720}
721
Paul Jakmab881c702010-11-23 16:35:42 +0000722/* Implement draft-scudder-idr-optional-transitive behaviour and
723 * avoid resetting sessions for malformed attributes which are
724 * are partial/optional and hence where the error likely was not
725 * introduced by the sending neighbour.
726 */
727static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000728bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
729 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000730{
Paul Jakma835315b2012-01-18 12:28:30 +0000731 struct peer *const peer = args->peer;
732 const u_int8_t flags = args->flags;
733 /* startp and length must be special-cased, as whether or not to
734 * send the attribute data with the NOTIFY depends on the error,
735 * the caller therefore signals this with the seperate length argument
736 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000737 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000738
Paul Jakmab881c702010-11-23 16:35:42 +0000739 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000740 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000741 {
742 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000743 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000744 return BGP_ATTR_PARSE_ERROR;
745
746 }
747
Paul Jakmabd471fe2012-03-15 11:30:00 +0000748 /* Adjust the stream getp to the end of the attribute, in case we can
749 * still proceed but the caller hasn't read all the attribute.
750 */
751 stream_set_getp (BGP_INPUT (peer),
752 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
753 + args->total);
754
Paul Jakma835315b2012-01-18 12:28:30 +0000755 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100756 /* where an attribute is relatively inconsequential, e.g. it does not
757 * affect route selection, and can be safely ignored, then any such
758 * attributes which are malformed should just be ignored and the route
759 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000760 */
761 case BGP_ATTR_AS4_AGGREGATOR:
762 case BGP_ATTR_AGGREGATOR:
763 case BGP_ATTR_ATOMIC_AGGREGATE:
764 return BGP_ATTR_PARSE_PROCEED;
765
766 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100767 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000768 */
769 case BGP_ATTR_ORIGIN:
770 case BGP_ATTR_AS_PATH:
771 case BGP_ATTR_NEXT_HOP:
772 case BGP_ATTR_MULTI_EXIT_DISC:
773 case BGP_ATTR_LOCAL_PREF:
774 case BGP_ATTR_COMMUNITIES:
775 case BGP_ATTR_ORIGINATOR_ID:
776 case BGP_ATTR_CLUSTER_LIST:
777 case BGP_ATTR_MP_REACH_NLRI:
778 case BGP_ATTR_MP_UNREACH_NLRI:
779 case BGP_ATTR_EXT_COMMUNITIES:
780 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000781 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000782 return BGP_ATTR_PARSE_ERROR;
783 }
784
785 /* Partial optional attributes that are malformed should not cause
786 * the whole session to be reset. Instead treat it as a withdrawal
787 * of the routes, if possible.
788 */
Paul Jakma835315b2012-01-18 12:28:30 +0000789 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
790 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
791 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000792 return BGP_ATTR_PARSE_WITHDRAW;
793
794 /* default to reset */
795 return BGP_ATTR_PARSE_ERROR;
796}
797
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400798/* Find out what is wrong with the path attribute flag bits and log the error.
799 "Flag bits" here stand for Optional, Transitive and Partial, but not for
800 Extended Length. Checking O/T/P bits at once implies, that the attribute
801 being diagnosed is defined by RFC as either a "well-known" or an "optional,
802 non-transitive" attribute. */
803static void
Paul Jakma835315b2012-01-18 12:28:30 +0000804bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
805 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400806)
807{
808 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000809 u_char real_flags = args->flags;
810 const u_int8_t attr_code = args->type;
811
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400812 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
813 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
814 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
815 if
816 (
817 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
818 CHECK_FLAG (real_flags, attr_flag_str[i].key)
819 )
820 {
Paul Jakma835315b2012-01-18 12:28:30 +0000821 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400822 LOOKUP (attr_str, attr_code),
823 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
824 attr_flag_str[i].str);
825 seen = 1;
826 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100827 if (!seen)
828 {
829 zlog (args->peer->log, LOG_DEBUG,
830 "Strange, %s called for attr %s, but no problem found with flags"
831 " (real flags 0x%x, desired 0x%x)",
832 __func__, LOOKUP (attr_str, attr_code),
833 real_flags, desired_flags);
834 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400835}
836
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000837/* Required flags for attributes. EXTLEN will be masked off when testing,
838 * as will PARTIAL for optional+transitive attributes.
839 */
840const u_int8_t attr_flags_values [] = {
841 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
842 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
843 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
844 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
845 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
846 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
847 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
848 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
849 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
850 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
851 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
852 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
853 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
854 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
855 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
856};
857static const size_t attr_flags_values_max =
858 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
859
860static int
Paul Jakma835315b2012-01-18 12:28:30 +0000861bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000862{
863 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000864 const u_int8_t flags = args->flags;
865 const u_int8_t attr_code = args->type;
866 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000867
868 /* there may be attributes we don't know about */
869 if (attr_code > attr_flags_values_max)
870 return 0;
871 if (attr_flags_values[attr_code] == 0)
872 return 0;
873
874 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
875 * 1."
876 */
877 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
878 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
879 {
880 zlog (peer->log, LOG_ERR,
881 "%s well-known attributes must have transitive flag set (%x)",
882 LOOKUP (attr_str, attr_code), flags);
883 return 1;
884 }
885
886 /* "For well-known attributes and for optional non-transitive attributes,
887 * the Partial bit MUST be set to 0."
888 */
889 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
890 {
891 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
892 {
893 zlog (peer->log, LOG_ERR,
894 "%s well-known attribute "
895 "must NOT have the partial flag set (%x)",
896 LOOKUP (attr_str, attr_code), flags);
897 return 1;
898 }
899 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
900 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
901 {
902 zlog (peer->log, LOG_ERR,
903 "%s optional + transitive attribute "
904 "must NOT have the partial flag set (%x)",
905 LOOKUP (attr_str, attr_code), flags);
906 return 1;
907 }
908 }
909
910 /* Optional transitive attributes may go through speakers that don't
911 * reocgnise them and set the Partial bit.
912 */
913 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
914 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
915 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
916
Paul Jakma683f2b82012-03-23 14:58:45 +0000917 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000918 == attr_flags_values[attr_code])
919 return 0;
920
Paul Jakma835315b2012-01-18 12:28:30 +0000921 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000922 return 1;
923}
924
paul718e3742002-12-13 20:15:29 +0000925/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000926static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000927bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000928{
Paul Jakma835315b2012-01-18 12:28:30 +0000929 struct peer *const peer = args->peer;
930 struct attr *const attr = args->attr;
931 const bgp_size_t length = args->length;
932
paul718e3742002-12-13 20:15:29 +0000933 /* If any recognized attribute has Attribute Length that conflicts
934 with the expected length (based on the attribute type code), then
935 the Error Subcode is set to Attribute Length Error. The Data
936 field contains the erroneous attribute (type, length and
937 value). */
938 if (length != 1)
939 {
940 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
941 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000942 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000943 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000944 args->total);
paul718e3742002-12-13 20:15:29 +0000945 }
946
947 /* Fetch origin attribute. */
948 attr->origin = stream_getc (BGP_INPUT (peer));
949
950 /* If the ORIGIN attribute has an undefined value, then the Error
951 Subcode is set to Invalid Origin Attribute. The Data field
952 contains the unrecognized attribute (type, length and value). */
953 if ((attr->origin != BGP_ORIGIN_IGP)
954 && (attr->origin != BGP_ORIGIN_EGP)
955 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
956 {
957 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
958 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000959 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000960 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000961 args->total);
paul718e3742002-12-13 20:15:29 +0000962 }
963
964 /* Set oring attribute flag. */
965 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
966
967 return 0;
968}
Paul Jakmaab005292010-11-27 22:48:34 +0000969
970/* Parse AS path information. This function is wrapper of
971 aspath_parse. */
972static int
Paul Jakma835315b2012-01-18 12:28:30 +0000973bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000974{
Paul Jakma835315b2012-01-18 12:28:30 +0000975 struct attr *const attr = args->attr;
976 struct peer *const peer = args->peer;
977 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000978
Paul Jakmaab005292010-11-27 22:48:34 +0000979 /*
980 * peer with AS4 => will get 4Byte ASnums
981 * otherwise, will get 16 Bit
982 */
983 attr->aspath = aspath_parse (peer->ibuf, length,
984 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
985
986 /* In case of IBGP, length will be zero. */
987 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000988 {
Paul Jakmab881c702010-11-23 16:35:42 +0000989 zlog (peer->log, LOG_ERR,
990 "Malformed AS path from %s, length is %d",
991 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000992 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000993 }
Chris Hallcddb8112010-08-09 22:31:37 +0400994
Paul Jakmaab005292010-11-27 22:48:34 +0000995 /* Set aspath attribute flag. */
996 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000997
Paul Jakmab881c702010-11-23 16:35:42 +0000998 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000999}
1000
Paul Jakmab881c702010-11-23 16:35:42 +00001001static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001002bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001003{
1004 /* These checks were part of bgp_attr_aspath, but with
1005 * as4 we should to check aspath things when
1006 * aspath synthesizing with as4_path has already taken place.
1007 * Otherwise we check ASPATH and use the synthesized thing, and that is
1008 * not right.
1009 * So do the checks later, i.e. here
1010 */
1011 struct bgp *bgp = peer->bgp;
1012 struct aspath *aspath;
1013
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001014 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001015 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1016 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001017 {
1018 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001019 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1020 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1021 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001022 }
1023
paul718e3742002-12-13 20:15:29 +00001024 /* First AS check for EBGP. */
1025 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1026 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001027 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001028 && ! aspath_firstas_check (attr->aspath, peer->as))
1029 {
1030 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001031 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001032 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1033 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1034 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001035 }
1036 }
1037
1038 /* local-as prepend */
1039 if (peer->change_local_as &&
1040 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1041 {
1042 aspath = aspath_dup (attr->aspath);
1043 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001044 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001045 attr->aspath = aspath_intern (aspath);
1046 }
1047
Paul Jakmab881c702010-11-23 16:35:42 +00001048 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001049}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001050
Paul Jakmaab005292010-11-27 22:48:34 +00001051/* Parse AS4 path information. This function is another wrapper of
1052 aspath_parse. */
1053static int
Paul Jakma835315b2012-01-18 12:28:30 +00001054bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001055{
Paul Jakma835315b2012-01-18 12:28:30 +00001056 struct peer *const peer = args->peer;
1057 struct attr *const attr = args->attr;
1058 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001059
Paul Jakmaab005292010-11-27 22:48:34 +00001060 *as4_path = aspath_parse (peer->ibuf, length, 1);
1061
Paul Jakmab881c702010-11-23 16:35:42 +00001062 /* In case of IBGP, length will be zero. */
1063 if (!*as4_path)
1064 {
1065 zlog (peer->log, LOG_ERR,
1066 "Malformed AS4 path from %s, length is %d",
1067 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001068 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001069 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001070 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001071 }
1072
Paul Jakmaab005292010-11-27 22:48:34 +00001073 /* Set aspath attribute flag. */
1074 if (as4_path)
1075 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1076
Paul Jakmab881c702010-11-23 16:35:42 +00001077 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001078}
1079
paul718e3742002-12-13 20:15:29 +00001080/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001081static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001082bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001083{
Paul Jakma835315b2012-01-18 12:28:30 +00001084 struct peer *const peer = args->peer;
1085 struct attr *const attr = args->attr;
1086 const bgp_size_t length = args->length;
1087
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001088 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001089
paul718e3742002-12-13 20:15:29 +00001090 /* Check nexthop attribute length. */
1091 if (length != 4)
1092 {
1093 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1094 length);
1095
Paul Jakma835315b2012-01-18 12:28:30 +00001096 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001097 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001098 args->total);
paul718e3742002-12-13 20:15:29 +00001099 }
1100
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001101 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1102 attribute must result in a NOTIFICATION message (this is implemented below).
1103 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1104 logged locally (this is implemented somewhere else). The UPDATE message
1105 gets ignored in any of these cases. */
1106 nexthop_n = stream_get_ipv4 (peer->ibuf);
1107 nexthop_h = ntohl (nexthop_n);
1108 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1109 {
1110 char buf[INET_ADDRSTRLEN];
1111 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1112 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001113 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001114 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001115 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001116 }
1117
1118 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001119 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1120
Paul Jakmab881c702010-11-23 16:35:42 +00001121 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001122}
1123
1124/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001125static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001126bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001127{
Paul Jakma835315b2012-01-18 12:28:30 +00001128 struct peer *const peer = args->peer;
1129 struct attr *const attr = args->attr;
1130 const bgp_size_t length = args->length;
1131
paul718e3742002-12-13 20:15:29 +00001132 /* Length check. */
1133 if (length != 4)
1134 {
1135 zlog (peer->log, LOG_ERR,
1136 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001137
Paul Jakma835315b2012-01-18 12:28:30 +00001138 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001139 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001140 args->total);
paul718e3742002-12-13 20:15:29 +00001141 }
1142
1143 attr->med = stream_getl (peer->ibuf);
1144
1145 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1146
Paul Jakmab881c702010-11-23 16:35:42 +00001147 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001148}
1149
1150/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001151static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001152bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001153{
Paul Jakma835315b2012-01-18 12:28:30 +00001154 struct peer *const peer = args->peer;
1155 struct attr *const attr = args->attr;
1156 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001157
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001158 /* Length check. */
1159 if (length != 4)
1160 {
Paul Jakma835315b2012-01-18 12:28:30 +00001161 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1162 length);
1163 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001164 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001165 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001166 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001167
paul718e3742002-12-13 20:15:29 +00001168 /* If it is contained in an UPDATE message that is received from an
1169 external peer, then this attribute MUST be ignored by the
1170 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001171 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001172 {
paul9985f832005-02-09 15:51:56 +00001173 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001174 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001175 }
1176
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001177 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001178
1179 /* Set atomic aggregate flag. */
1180 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1181
Paul Jakmab881c702010-11-23 16:35:42 +00001182 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001183}
1184
1185/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001186static int
Paul Jakma835315b2012-01-18 12:28:30 +00001187bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001188{
Paul Jakma835315b2012-01-18 12:28:30 +00001189 struct peer *const peer = args->peer;
1190 struct attr *const attr = args->attr;
1191 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001192
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001193 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001194 if (length != 0)
1195 {
Paul Jakma835315b2012-01-18 12:28:30 +00001196 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1197 length);
1198 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001199 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001200 args->total);
paul718e3742002-12-13 20:15:29 +00001201 }
1202
1203 /* Set atomic aggregate flag. */
1204 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1205
Paul Jakmab881c702010-11-23 16:35:42 +00001206 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001207}
1208
1209/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001210static int
Paul Jakma835315b2012-01-18 12:28:30 +00001211bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001212{
Paul Jakma835315b2012-01-18 12:28:30 +00001213 struct peer *const peer = args->peer;
1214 struct attr *const attr = args->attr;
1215 const bgp_size_t length = args->length;
1216
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001217 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001218 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001219
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001220 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001221 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001222 wantedlen = 8;
1223
1224 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001225 {
Paul Jakma835315b2012-01-18 12:28:30 +00001226 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1227 wantedlen, length);
1228 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001229 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001230 args->total);
paul718e3742002-12-13 20:15:29 +00001231 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001232
1233 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1234 attre->aggregator_as = stream_getl (peer->ibuf);
1235 else
1236 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001237 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001238
1239 /* Set atomic aggregate flag. */
1240 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1241
Paul Jakmab881c702010-11-23 16:35:42 +00001242 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001243}
1244
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001245/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001246static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001247bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1248 as_t *as4_aggregator_as,
1249 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001250{
Paul Jakma835315b2012-01-18 12:28:30 +00001251 struct peer *const peer = args->peer;
1252 struct attr *const attr = args->attr;
1253 const bgp_size_t length = args->length;
1254
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001255 if (length != 8)
1256 {
Paul Jakma835315b2012-01-18 12:28:30 +00001257 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1258 length);
1259 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001260 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001261 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001262 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001263
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001264 *as4_aggregator_as = stream_getl (peer->ibuf);
1265 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1266
1267 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1268
Paul Jakmab881c702010-11-23 16:35:42 +00001269 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001270}
1271
1272/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1273 */
Paul Jakmab881c702010-11-23 16:35:42 +00001274static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001275bgp_attr_munge_as4_attrs (struct peer *const peer,
1276 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001277 struct aspath *as4_path, as_t as4_aggregator,
1278 struct in_addr *as4_aggregator_addr)
1279{
1280 int ignore_as4_path = 0;
1281 struct aspath *newpath;
1282 struct attr_extra *attre = attr->extra;
1283
Paul Jakmab881c702010-11-23 16:35:42 +00001284 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001285 {
1286 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1287 * if given.
1288 * It is worth a warning though, because the peer really
1289 * should not send them
1290 */
1291 if (BGP_DEBUG(as4, AS4))
1292 {
1293 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1294 zlog_debug ("[AS4] %s %s AS4_PATH",
1295 peer->host, "AS4 capable peer, yet it sent");
1296
1297 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1298 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1299 peer->host, "AS4 capable peer, yet it sent");
1300 }
1301
Paul Jakmab881c702010-11-23 16:35:42 +00001302 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001303 }
1304
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001305 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1306 * because that may override AS4_PATH
1307 */
1308 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1309 {
Paul Jakmab881c702010-11-23 16:35:42 +00001310 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001311 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001312 assert (attre);
1313
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001314 /* received both.
1315 * if the as_number in aggregator is not AS_TRANS,
1316 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1317 * and the Aggregator shall be taken as
1318 * info on the aggregating node, and the AS_PATH
1319 * shall be taken as the AS_PATH
1320 * otherwise
1321 * the Aggregator shall be ignored and the
1322 * AS4_AGGREGATOR shall be taken as the
1323 * Aggregating node and the AS_PATH is to be
1324 * constructed "as in all other cases"
1325 */
Paul Jakmab881c702010-11-23 16:35:42 +00001326 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001327 {
1328 /* ignore */
1329 if ( BGP_DEBUG(as4, AS4))
1330 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1331 " send AGGREGATOR != AS_TRANS and"
1332 " AS4_AGGREGATOR, so ignore"
1333 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1334 ignore_as4_path = 1;
1335 }
1336 else
1337 {
1338 /* "New_aggregator shall be taken as aggregator" */
1339 attre->aggregator_as = as4_aggregator;
1340 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1341 }
1342 }
1343 else
1344 {
1345 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1346 * That is bogus - but reading the conditions
1347 * we have to handle AS4_AGGREGATOR as if it were
1348 * AGGREGATOR in that case
1349 */
1350 if ( BGP_DEBUG(as4, AS4))
1351 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1352 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1353 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001354 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001355 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1356 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1357 }
1358 }
1359
1360 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001361 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001362 {
1363 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001364 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001365 attr->aspath = aspath_intern (newpath);
1366 }
Paul Jakmab881c702010-11-23 16:35:42 +00001367 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001368}
1369
paul718e3742002-12-13 20:15:29 +00001370/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001371static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001372bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001373{
Paul Jakma835315b2012-01-18 12:28:30 +00001374 struct peer *const peer = args->peer;
1375 struct attr *const attr = args->attr;
1376 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001377
paul718e3742002-12-13 20:15:29 +00001378 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001379 {
1380 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001381 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001382 }
Paul Jakma0c466382010-12-05 17:17:26 +00001383
1384 attr->community =
1385 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1386
1387 /* XXX: fix community_parse to use stream API and remove this */
1388 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001389
Paul Jakma0c466382010-12-05 17:17:26 +00001390 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001391 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001392 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001393 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001394
paul718e3742002-12-13 20:15:29 +00001395 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1396
Paul Jakmab881c702010-11-23 16:35:42 +00001397 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001398}
1399
1400/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001401static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001402bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001403{
Paul Jakma835315b2012-01-18 12:28:30 +00001404 struct peer *const peer = args->peer;
1405 struct attr *const attr = args->attr;
1406 const bgp_size_t length = args->length;
1407
Denis Ovsienkod595b562011-09-30 15:08:54 +04001408 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001409 if (length != 4)
1410 {
1411 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1412
Paul Jakma835315b2012-01-18 12:28:30 +00001413 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001414 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001415 args->total);
paul718e3742002-12-13 20:15:29 +00001416 }
1417
Paul Jakmafb982c22007-05-04 20:15:47 +00001418 (bgp_attr_extra_get (attr))->originator_id.s_addr
1419 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001420
1421 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1422
Paul Jakmab881c702010-11-23 16:35:42 +00001423 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001424}
1425
1426/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001427static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001428bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001429{
Paul Jakma835315b2012-01-18 12:28:30 +00001430 struct peer *const peer = args->peer;
1431 struct attr *const attr = args->attr;
1432 const bgp_size_t length = args->length;
1433
paul718e3742002-12-13 20:15:29 +00001434 /* Check length. */
1435 if (length % 4)
1436 {
1437 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1438
Paul Jakma835315b2012-01-18 12:28:30 +00001439 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1440 args->total);
paul718e3742002-12-13 20:15:29 +00001441 }
1442
Paul Jakmafb982c22007-05-04 20:15:47 +00001443 (bgp_attr_extra_get (attr))->cluster
1444 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001445
1446 /* XXX: Fix cluster_parse to use stream API and then remove this */
1447 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001448
1449 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1450
Paul Jakmab881c702010-11-23 16:35:42 +00001451 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001452}
1453
1454/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001455int
Paul Jakma835315b2012-01-18 12:28:30 +00001456bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1457 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001458{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001459 afi_t afi;
1460 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001461 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001462 size_t start;
paul718e3742002-12-13 20:15:29 +00001463 int ret;
1464 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001465 struct peer *const peer = args->peer;
1466 struct attr *const attr = args->attr;
1467 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001468 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001469
paul718e3742002-12-13 20:15:29 +00001470 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001471 s = BGP_INPUT(peer);
1472 start = stream_get_getp(s);
1473
1474 /* safe to read statically sized header? */
1475#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001476#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001477 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001478 {
1479 zlog_info ("%s: %s sent invalid length, %lu",
1480 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001481 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001482 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001483
paul718e3742002-12-13 20:15:29 +00001484 /* Load AFI, SAFI. */
1485 afi = stream_getw (s);
1486 safi = stream_getc (s);
1487
1488 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001489 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001490
Paul Jakma03292802008-06-07 20:37:10 +00001491 if (LEN_LEFT < attre->mp_nexthop_len)
1492 {
1493 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1494 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001495 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001496 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001497
paul718e3742002-12-13 20:15:29 +00001498 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001499 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001500 {
1501 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001502 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001503 /* Probably needed for RFC 2283 */
1504 if (attr->nexthop.s_addr == 0)
1505 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001506 break;
1507 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001508 stream_getl (s); /* RD high */
1509 stream_getl (s); /* RD low */
1510 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001511 break;
1512#ifdef HAVE_IPV6
1513 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001514 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001515 break;
1516 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001517 stream_get (&attre->mp_nexthop_global, s, 16);
1518 stream_get (&attre->mp_nexthop_local, s, 16);
1519 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001520 {
1521 char buf1[INET6_ADDRSTRLEN];
1522 char buf2[INET6_ADDRSTRLEN];
1523
1524 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001525 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 +00001526 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001527 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001528 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001529 buf2, INET6_ADDRSTRLEN));
1530
Paul Jakmafb982c22007-05-04 20:15:47 +00001531 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001532 }
1533 break;
1534#endif /* HAVE_IPV6 */
1535 default:
Paul Jakma03292802008-06-07 20:37:10 +00001536 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1537 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001538 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001539 }
1540
Paul Jakma03292802008-06-07 20:37:10 +00001541 if (!LEN_LEFT)
1542 {
1543 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1544 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001545 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001546 }
paul718e3742002-12-13 20:15:29 +00001547
Paul Jakma6e4ab122007-04-10 19:36:48 +00001548 {
1549 u_char val;
1550 if ((val = stream_getc (s)))
1551 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1552 peer->host, val);
1553 }
1554
1555 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001556 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001557 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001558 {
1559 zlog_info ("%s: (%s) Failed to read NLRI",
1560 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001561 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001562 }
paul718e3742002-12-13 20:15:29 +00001563
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001564 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001565 {
1566 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001567 if (ret < 0)
1568 {
1569 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1570 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001571 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001572 }
paul718e3742002-12-13 20:15:29 +00001573 }
1574
1575 mp_update->afi = afi;
1576 mp_update->safi = safi;
1577 mp_update->nlri = stream_pnt (s);
1578 mp_update->length = nlri_len;
1579
paul9985f832005-02-09 15:51:56 +00001580 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001581
Paul Jakmab881c702010-11-23 16:35:42 +00001582 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001583#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001584}
1585
1586/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001587int
Paul Jakma835315b2012-01-18 12:28:30 +00001588bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001589 struct bgp_nlri *mp_withdraw)
1590{
1591 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001592 afi_t afi;
1593 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001594 u_int16_t withdraw_len;
1595 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001596 struct peer *const peer = args->peer;
1597 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001598
1599 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001600
1601#define BGP_MP_UNREACH_MIN_SIZE 3
1602 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001603 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001604
paul718e3742002-12-13 20:15:29 +00001605 afi = stream_getw (s);
1606 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001607
1608 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001609
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001610 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001611 {
1612 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1613 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001614 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001615 }
1616
1617 mp_withdraw->afi = afi;
1618 mp_withdraw->safi = safi;
1619 mp_withdraw->nlri = stream_pnt (s);
1620 mp_withdraw->length = withdraw_len;
1621
paul9985f832005-02-09 15:51:56 +00001622 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001623
Paul Jakmab881c702010-11-23 16:35:42 +00001624 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001625}
1626
1627/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001628static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001629bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001630{
Paul Jakma835315b2012-01-18 12:28:30 +00001631 struct peer *const peer = args->peer;
1632 struct attr *const attr = args->attr;
1633 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001634
paul718e3742002-12-13 20:15:29 +00001635 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001636 {
1637 if (attr->extra)
1638 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001639 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001640 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001641 }
Paul Jakma0c466382010-12-05 17:17:26 +00001642
1643 (bgp_attr_extra_get (attr))->ecommunity =
1644 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1645 /* XXX: fix ecommunity_parse to use stream API */
1646 stream_forward_getp (peer->ibuf, length);
1647
1648 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001649 return bgp_attr_malformed (args,
1650 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1651 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001652
paul718e3742002-12-13 20:15:29 +00001653 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1654
Paul Jakmab881c702010-11-23 16:35:42 +00001655 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001656}
1657
1658/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001659static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001660bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001661{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001662 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001663 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001664 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001665 struct peer *const peer = args->peer;
1666 struct attr *const attr = args->attr;
1667 u_char *const startp = args->startp;
1668 const u_char type = args->type;
1669 const u_char flag = args->flags;
1670 const bgp_size_t length = args->length;
1671
paul718e3742002-12-13 20:15:29 +00001672
hassof4184462005-02-01 20:13:16 +00001673 if (BGP_DEBUG (normal, NORMAL))
1674 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1675 peer->host, type, length);
1676
paul718e3742002-12-13 20:15:29 +00001677 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001678 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001679 "Unknown attribute type %d length %d is received", type, length);
1680
1681 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001682 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001683
paul718e3742002-12-13 20:15:29 +00001684 /* If any of the mandatory well-known attributes are not recognized,
1685 then the Error Subcode is set to Unrecognized Well-known
1686 Attribute. The Data field contains the unrecognized attribute
1687 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001688 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001689 {
Paul Jakma835315b2012-01-18 12:28:30 +00001690 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001691 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001692 args->total);
paul718e3742002-12-13 20:15:29 +00001693 }
1694
1695 /* Unrecognized non-transitive optional attributes must be quietly
1696 ignored and not passed along to other BGP peers. */
1697 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001698 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001699
1700 /* If a path with recognized transitive optional attribute is
1701 accepted and passed along to other BGP peers and the Partial bit
1702 in the Attribute Flags octet is set to 1 by some previous AS, it
1703 is not set back to 0 by the current AS. */
1704 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1705
1706 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001707 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001708 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001709
Paul Jakmafb982c22007-05-04 20:15:47 +00001710 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001711
1712 if (transit->val)
1713 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1714 transit->length + total);
1715 else
1716 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1717
1718 memcpy (transit->val + transit->length, startp, total);
1719 transit->length += total;
1720
Paul Jakmab881c702010-11-23 16:35:42 +00001721 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001722}
1723
1724/* Read attribute of update packet. This function is called from
Andrew Certain8b366b92012-11-07 23:50:08 +00001725 bgp_update_receive() in bgp_packet.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001726bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001727bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1728 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1729{
1730 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001731 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001732 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001733 bgp_size_t length;
1734 u_char *startp, *endp;
1735 u_char *attr_endp;
1736 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001737 /* we need the as4_path only until we have synthesized the as_path with it */
1738 /* same goes for as4_aggregator */
1739 struct aspath *as4_path = NULL;
1740 as_t as4_aggregator = 0;
1741 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001742
1743 /* Initialize bitmap. */
1744 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1745
1746 /* End pointer of BGP attribute. */
1747 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001748
paul718e3742002-12-13 20:15:29 +00001749 /* Get attributes to the end of attribute length. */
1750 while (BGP_INPUT_PNT (peer) < endp)
1751 {
1752 /* Check remaining length check.*/
1753 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1754 {
gdtc29fdba2004-12-09 14:46:46 +00001755 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001756 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001757 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001758 peer->host,
1759 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001760
1761 bgp_notify_send (peer,
1762 BGP_NOTIFY_UPDATE_ERR,
1763 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001764 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001765 }
1766
1767 /* Fetch attribute flag and type. */
1768 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001769 /* "The lower-order four bits of the Attribute Flags octet are
1770 unused. They MUST be zero when sent and MUST be ignored when
1771 received." */
1772 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001773 type = stream_getc (BGP_INPUT (peer));
1774
Paul Jakma370b64a2007-12-22 16:49:52 +00001775 /* Check whether Extended-Length applies and is in bounds */
1776 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1777 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1778 {
1779 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001780 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001781 peer->host,
1782 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1783
1784 bgp_notify_send (peer,
1785 BGP_NOTIFY_UPDATE_ERR,
1786 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001787 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001788 }
Paul Jakma835315b2012-01-18 12:28:30 +00001789
paul718e3742002-12-13 20:15:29 +00001790 /* Check extended attribue length bit. */
1791 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1792 length = stream_getw (BGP_INPUT (peer));
1793 else
1794 length = stream_getc (BGP_INPUT (peer));
1795
1796 /* If any attribute appears more than once in the UPDATE
1797 message, then the Error Subcode is set to Malformed Attribute
1798 List. */
1799
1800 if (CHECK_BITMAP (seen, type))
1801 {
1802 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001803 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001804 peer->host, type);
1805
1806 bgp_notify_send (peer,
1807 BGP_NOTIFY_UPDATE_ERR,
1808 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001809 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001810 }
1811
1812 /* Set type to bitmap to check duplicate attribute. `type' is
1813 unsigned char so it never overflow bitmap range. */
1814
1815 SET_BITMAP (seen, type);
1816
1817 /* Overflow check. */
1818 attr_endp = BGP_INPUT_PNT (peer) + length;
1819
1820 if (attr_endp > endp)
1821 {
1822 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001823 "%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 +00001824 bgp_notify_send (peer,
1825 BGP_NOTIFY_UPDATE_ERR,
1826 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001827 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001828 }
Paul Jakma835315b2012-01-18 12:28:30 +00001829
1830 struct bgp_attr_parser_args attr_args = {
1831 .peer = peer,
1832 .length = length,
1833 .attr = attr,
1834 .type = type,
1835 .flags = flag,
1836 .startp = startp,
1837 .total = attr_endp - startp,
1838 };
1839
1840
1841 /* If any recognized attribute has Attribute Flags that conflict
1842 with the Attribute Type Code, then the Error Subcode is set to
1843 Attribute Flags Error. The Data field contains the erroneous
1844 attribute (type, length and value). */
1845 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001846 {
1847 bgp_attr_parse_ret_t ret;
1848 ret = bgp_attr_malformed (&attr_args,
1849 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1850 attr_args.total);
1851 if (ret == BGP_ATTR_PARSE_PROCEED)
1852 continue;
1853 return ret;
1854 }
paul718e3742002-12-13 20:15:29 +00001855
1856 /* OK check attribute and store it's value. */
1857 switch (type)
1858 {
1859 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001860 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001861 break;
1862 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001863 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001864 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001865 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001866 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001867 break;
paul718e3742002-12-13 20:15:29 +00001868 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001869 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001870 break;
1871 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001872 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001873 break;
1874 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001875 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001876 break;
1877 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001878 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001879 break;
1880 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001881 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001882 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001883 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001884 ret = bgp_attr_as4_aggregator (&attr_args,
1885 &as4_aggregator,
1886 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001887 break;
paul718e3742002-12-13 20:15:29 +00001888 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001889 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001890 break;
1891 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001892 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001893 break;
1894 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001895 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001896 break;
1897 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001898 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001899 break;
1900 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001901 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001902 break;
1903 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001904 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001905 break;
1906 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001907 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001908 break;
1909 }
Paul Jakmab881c702010-11-23 16:35:42 +00001910
1911 /* If hard error occured immediately return to the caller. */
1912 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001913 {
1914 zlog (peer->log, LOG_WARNING,
1915 "%s: Attribute %s, parse error",
1916 peer->host,
1917 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001918 bgp_notify_send (peer,
1919 BGP_NOTIFY_UPDATE_ERR,
1920 BGP_NOTIFY_UPDATE_MAL_ATTR);
1921 if (as4_path)
1922 aspath_unintern (&as4_path);
1923 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001924 }
Paul Jakmab881c702010-11-23 16:35:42 +00001925 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1926 {
1927
1928 zlog (peer->log, LOG_WARNING,
1929 "%s: Attribute %s, parse error - treating as withdrawal",
1930 peer->host,
1931 LOOKUP (attr_str, type));
1932 if (as4_path)
1933 aspath_unintern (&as4_path);
1934 return ret;
1935 }
1936
paul718e3742002-12-13 20:15:29 +00001937 /* Check the fetched length. */
1938 if (BGP_INPUT_PNT (peer) != attr_endp)
1939 {
1940 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001941 "%s: BGP attribute %s, fetch error",
1942 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001943 bgp_notify_send (peer,
1944 BGP_NOTIFY_UPDATE_ERR,
1945 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001946 if (as4_path)
1947 aspath_unintern (&as4_path);
1948 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001949 }
1950 }
1951
1952 /* Check final read pointer is same as end pointer. */
1953 if (BGP_INPUT_PNT (peer) != endp)
1954 {
1955 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001956 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001957 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001958 bgp_notify_send (peer,
1959 BGP_NOTIFY_UPDATE_ERR,
1960 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001961 if (as4_path)
1962 aspath_unintern (&as4_path);
1963 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001964 }
1965
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001966 /*
1967 * At this place we can see whether we got AS4_PATH and/or
1968 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1969 * We can not do this before we've read all attributes because
1970 * the as4 handling does not say whether AS4_PATH has to be sent
1971 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1972 * in relationship to AGGREGATOR.
1973 * So, to be defensive, we are not relying on any order and read
1974 * all attributes first, including these 32bit ones, and now,
1975 * afterwards, we look what and if something is to be done for as4.
1976 */
Paul Jakma835315b2012-01-18 12:28:30 +00001977 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001978 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001979 {
1980 if (as4_path)
1981 aspath_unintern (&as4_path);
1982 return BGP_ATTR_PARSE_ERROR;
1983 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001984
1985 /* At this stage, we have done all fiddling with as4, and the
1986 * resulting info is in attr->aggregator resp. attr->aspath
1987 * so we can chuck as4_aggregator and as4_path alltogether in
1988 * order to save memory
1989 */
Paul Jakmab881c702010-11-23 16:35:42 +00001990 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001991 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001992 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001993 /* The flag that we got this is still there, but that does not
1994 * do any trouble
1995 */
1996 }
1997 /*
1998 * The "rest" of the code does nothing with as4_aggregator.
1999 * there is no memory attached specifically which is not part
2000 * of the attr.
2001 * so ignoring just means do nothing.
2002 */
2003 /*
2004 * Finally do the checks on the aspath we did not do yet
2005 * because we waited for a potentially synthesized aspath.
2006 */
Paul Jakmab881c702010-11-23 16:35:42 +00002007 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002008 {
Paul Jakma835315b2012-01-18 12:28:30 +00002009 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00002010 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002011 return ret;
2012 }
2013
paul718e3742002-12-13 20:15:29 +00002014 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002015 if (attr->extra && attr->extra->transit)
2016 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002017
Paul Jakmab881c702010-11-23 16:35:42 +00002018 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002019}
2020
2021/* Well-known attribute check. */
2022int
2023bgp_attr_check (struct peer *peer, struct attr *attr)
2024{
2025 u_char type = 0;
2026
2027 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2028 type = BGP_ATTR_ORIGIN;
2029
2030 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2031 type = BGP_ATTR_AS_PATH;
2032
2033 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2034 type = BGP_ATTR_NEXT_HOP;
2035
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002036 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002037 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2038 type = BGP_ATTR_LOCAL_PREF;
2039
2040 if (type)
2041 {
2042 zlog (peer->log, LOG_WARNING,
2043 "%s Missing well-known attribute %d.",
2044 peer->host, type);
2045 bgp_notify_send_with_data (peer,
2046 BGP_NOTIFY_UPDATE_ERR,
2047 BGP_NOTIFY_UPDATE_MISS_ATTR,
2048 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002049 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002050 }
Paul Jakmab881c702010-11-23 16:35:42 +00002051 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002052}
2053
2054int stream_put_prefix (struct stream *, struct prefix *);
2055
2056/* Make attribute packet. */
2057bgp_size_t
2058bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2059 struct stream *s, struct attr *attr, struct prefix *p,
2060 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002061 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002062{
paulfe69a502005-09-10 16:55:02 +00002063 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002064 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002065 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002066 int send_as4_path = 0;
2067 int send_as4_aggregator = 0;
2068 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002069
2070 if (! bgp)
2071 bgp = bgp_get_default ();
2072
2073 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002074 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002075
2076 /* Origin attribute. */
2077 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2078 stream_putc (s, BGP_ATTR_ORIGIN);
2079 stream_putc (s, 1);
2080 stream_putc (s, attr->origin);
2081
2082 /* AS path attribute. */
2083
2084 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002085 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002086 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002087 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002088 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002089 {
2090 aspath = aspath_dup (attr->aspath);
2091
2092 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2093 {
2094 /* Strip the confed info, and then stuff our path CONFED_ID
2095 on the front */
2096 aspath = aspath_delete_confed_seq (aspath);
2097 aspath = aspath_add_seq (aspath, bgp->confed_id);
2098 }
2099 else
2100 {
Andrew Certain9d3f9702012-11-07 23:50:07 +00002101 if (peer->change_local_as) {
2102 /* If replace-as is specified, we only use the change_local_as when
2103 advertising routes. */
2104 if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
2105 aspath = aspath_add_seq (aspath, peer->local_as);
2106 }
paul718e3742002-12-13 20:15:29 +00002107 aspath = aspath_add_seq (aspath, peer->change_local_as);
Andrew Certain9d3f9702012-11-07 23:50:07 +00002108 } else {
2109 aspath = aspath_add_seq (aspath, peer->local_as);
2110 }
paul718e3742002-12-13 20:15:29 +00002111 }
2112 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002113 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002114 {
2115 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2116 aspath = aspath_dup (attr->aspath);
2117 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2118 }
2119 else
2120 aspath = attr->aspath;
2121
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002122 /* If peer is not AS4 capable, then:
2123 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2124 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2125 * types are in it (i.e. exclude them if they are there)
2126 * AND do this only if there is at least one asnum > 65535 in the path!
2127 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2128 * all ASnums > 65535 to BGP_AS_TRANS
2129 */
paul718e3742002-12-13 20:15:29 +00002130
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002131 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2132 stream_putc (s, BGP_ATTR_AS_PATH);
2133 aspath_sizep = stream_get_endp (s);
2134 stream_putw (s, 0);
2135 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2136
2137 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2138 * in the path
2139 */
2140 if (!use32bit && aspath_has_as4 (aspath))
2141 send_as4_path = 1; /* we'll do this later, at the correct place */
2142
paul718e3742002-12-13 20:15:29 +00002143 /* Nexthop attribute. */
2144 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2145 {
2146 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2147 stream_putc (s, BGP_ATTR_NEXT_HOP);
2148 stream_putc (s, 4);
2149 if (safi == SAFI_MPLS_VPN)
2150 {
2151 if (attr->nexthop.s_addr == 0)
2152 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2153 else
2154 stream_put_ipv4 (s, attr->nexthop.s_addr);
2155 }
2156 else
2157 stream_put_ipv4 (s, attr->nexthop.s_addr);
2158 }
2159
2160 /* MED attribute. */
2161 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2162 {
2163 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2164 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2165 stream_putc (s, 4);
2166 stream_putl (s, attr->med);
2167 }
2168
2169 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002170 if (peer->sort == BGP_PEER_IBGP ||
2171 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002172 {
2173 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2174 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2175 stream_putc (s, 4);
2176 stream_putl (s, attr->local_pref);
2177 }
2178
2179 /* Atomic aggregate. */
2180 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2181 {
2182 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2183 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2184 stream_putc (s, 0);
2185 }
2186
2187 /* Aggregator. */
2188 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2189 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002190 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002191
2192 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002193 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2194 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002195
2196 if (use32bit)
2197 {
2198 /* AS4 capable peer */
2199 stream_putc (s, 8);
2200 stream_putl (s, attr->extra->aggregator_as);
2201 }
2202 else
2203 {
2204 /* 2-byte AS peer */
2205 stream_putc (s, 6);
2206
2207 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2208 if ( attr->extra->aggregator_as > 65535 )
2209 {
2210 stream_putw (s, BGP_AS_TRANS);
2211
2212 /* we have to send AS4_AGGREGATOR, too.
2213 * we'll do that later in order to send attributes in ascending
2214 * order.
2215 */
2216 send_as4_aggregator = 1;
2217 }
2218 else
2219 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2220 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002221 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002222 }
2223
2224 /* Community attribute. */
2225 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2226 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2227 {
2228 if (attr->community->size * 4 > 255)
2229 {
2230 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2231 stream_putc (s, BGP_ATTR_COMMUNITIES);
2232 stream_putw (s, attr->community->size * 4);
2233 }
2234 else
2235 {
2236 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2237 stream_putc (s, BGP_ATTR_COMMUNITIES);
2238 stream_putc (s, attr->community->size * 4);
2239 }
2240 stream_put (s, attr->community->val, attr->community->size * 4);
2241 }
2242
2243 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002244 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002245 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002246 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002247 {
2248 /* Originator ID. */
2249 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2250 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2251 stream_putc (s, 4);
2252
2253 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002254 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002255 else
2256 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002257
2258 /* Cluster list. */
2259 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2260 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2261
Paul Jakma9eda90c2007-08-30 13:36:17 +00002262 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002263 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002264 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002265 /* If this peer configuration's parent BGP has cluster_id. */
2266 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2267 stream_put_in_addr (s, &bgp->cluster_id);
2268 else
2269 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002270 stream_put (s, attr->extra->cluster->list,
2271 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002272 }
2273 else
2274 {
2275 stream_putc (s, 4);
2276 /* If this peer configuration's parent BGP has cluster_id. */
2277 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2278 stream_put_in_addr (s, &bgp->cluster_id);
2279 else
2280 stream_put_in_addr (s, &bgp->router_id);
2281 }
2282 }
2283
2284#ifdef HAVE_IPV6
2285 /* If p is IPv6 address put it into attribute. */
2286 if (p->family == AF_INET6)
2287 {
2288 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002289 struct attr_extra *attre = attr->extra;
2290
2291 assert (attr->extra);
2292
paul718e3742002-12-13 20:15:29 +00002293 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2294 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002295 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002296 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002297 stream_putw (s, AFI_IP6); /* AFI */
2298 stream_putc (s, safi); /* SAFI */
2299
Paul Jakmafb982c22007-05-04 20:15:47 +00002300 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002301
Paul Jakmafb982c22007-05-04 20:15:47 +00002302 if (attre->mp_nexthop_len == 16)
2303 stream_put (s, &attre->mp_nexthop_global, 16);
2304 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002305 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002306 stream_put (s, &attre->mp_nexthop_global, 16);
2307 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002308 }
2309
2310 /* SNPA */
2311 stream_putc (s, 0);
2312
paul718e3742002-12-13 20:15:29 +00002313 /* Prefix write. */
2314 stream_put_prefix (s, p);
2315
2316 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002317 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002318 }
2319#endif /* HAVE_IPV6 */
2320
2321 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2322 {
2323 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002324
2325 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2326 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002327 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002328 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002329 stream_putw (s, AFI_IP); /* AFI */
2330 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2331
2332 stream_putc (s, 4);
2333 stream_put_ipv4 (s, attr->nexthop.s_addr);
2334
2335 /* SNPA */
2336 stream_putc (s, 0);
2337
paul718e3742002-12-13 20:15:29 +00002338 /* Prefix write. */
2339 stream_put_prefix (s, p);
2340
2341 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002342 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002343 }
2344
2345 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2346 {
2347 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002348
2349 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2350 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002351 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002352 stream_putc (s, 0); /* Length of this attribute. */
2353 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002354 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002355
2356 stream_putc (s, 12);
2357 stream_putl (s, 0);
2358 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002359 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002360
2361 /* SNPA */
2362 stream_putc (s, 0);
2363
paul718e3742002-12-13 20:15:29 +00002364 /* Tag, RD, Prefix write. */
2365 stream_putc (s, p->prefixlen + 88);
2366 stream_put (s, tag, 3);
2367 stream_put (s, prd->val, 8);
2368 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2369
2370 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002371 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002372 }
2373
2374 /* Extended Communities attribute. */
2375 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2376 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2377 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002378 struct attr_extra *attre = attr->extra;
2379
2380 assert (attre);
2381
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002382 if (peer->sort == BGP_PEER_IBGP
2383 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002384 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002385 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002386 {
2387 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2388 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002389 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002390 }
2391 else
2392 {
2393 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2394 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002395 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002396 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002397 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002398 }
2399 else
2400 {
paul5228ad22004-06-04 17:58:18 +00002401 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002402 int tbit;
2403 int ecom_tr_size = 0;
2404 int i;
2405
Paul Jakmafb982c22007-05-04 20:15:47 +00002406 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002407 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002408 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002409 tbit = *pnt;
2410
2411 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2412 continue;
2413
2414 ecom_tr_size++;
2415 }
2416
2417 if (ecom_tr_size)
2418 {
2419 if (ecom_tr_size * 8 > 255)
2420 {
2421 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2422 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2423 stream_putw (s, ecom_tr_size * 8);
2424 }
2425 else
2426 {
2427 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2428 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2429 stream_putc (s, ecom_tr_size * 8);
2430 }
2431
Paul Jakmafb982c22007-05-04 20:15:47 +00002432 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002433 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002434 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002435 tbit = *pnt;
2436
2437 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2438 continue;
2439
2440 stream_put (s, pnt, 8);
2441 }
2442 }
paul718e3742002-12-13 20:15:29 +00002443 }
paul718e3742002-12-13 20:15:29 +00002444 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002445
2446 if ( send_as4_path )
2447 {
2448 /* If the peer is NOT As4 capable, AND */
2449 /* there are ASnums > 65535 in path THEN
2450 * give out AS4_PATH */
2451
2452 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2453 * path segments!
2454 * Hm, I wonder... confederation things *should* only be at
2455 * the beginning of an aspath, right? Then we should use
2456 * aspath_delete_confed_seq for this, because it is already
2457 * there! (JK)
2458 * Folks, talk to me: what is reasonable here!?
2459 */
2460 aspath = aspath_delete_confed_seq (aspath);
2461
2462 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2463 stream_putc (s, BGP_ATTR_AS4_PATH);
2464 aspath_sizep = stream_get_endp (s);
2465 stream_putw (s, 0);
2466 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2467 }
2468
2469 if (aspath != attr->aspath)
2470 aspath_free (aspath);
2471
2472 if ( send_as4_aggregator )
2473 {
2474 assert (attr->extra);
2475
2476 /* send AS4_AGGREGATOR, at this place */
2477 /* this section of code moved here in order to ensure the correct
2478 * *ascending* order of attributes
2479 */
2480 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2481 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2482 stream_putc (s, 8);
2483 stream_putl (s, attr->extra->aggregator_as);
2484 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2485 }
Paul Jakma41367172007-08-06 15:24:51 +00002486
paul718e3742002-12-13 20:15:29 +00002487 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002488 if (attr->extra && attr->extra->transit)
2489 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002490
2491 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002492 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002493}
2494
2495bgp_size_t
2496bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2497 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002498 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002499{
2500 unsigned long cp;
2501 unsigned long attrlen_pnt;
2502 bgp_size_t size;
2503
paul9985f832005-02-09 15:51:56 +00002504 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002505
2506 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2507 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2508
paul9985f832005-02-09 15:51:56 +00002509 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002510 stream_putc (s, 0); /* Length of this attribute. */
2511
2512 stream_putw (s, family2afi (p->family));
2513
2514 if (safi == SAFI_MPLS_VPN)
2515 {
2516 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002517 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002518
2519 /* prefix. */
2520 stream_putc (s, p->prefixlen + 88);
2521 stream_put (s, tag, 3);
2522 stream_put (s, prd->val, 8);
2523 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2524 }
2525 else
2526 {
2527 /* SAFI */
2528 stream_putc (s, safi);
2529
2530 /* prefix */
2531 stream_put_prefix (s, p);
2532 }
2533
2534 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002535 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002536 stream_putc_at (s, attrlen_pnt, size);
2537
paul9985f832005-02-09 15:51:56 +00002538 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002539}
2540
2541/* Initialization of attribute. */
2542void
paulfe69a502005-09-10 16:55:02 +00002543bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002544{
paul718e3742002-12-13 20:15:29 +00002545 aspath_init ();
2546 attrhash_init ();
2547 community_init ();
2548 ecommunity_init ();
2549 cluster_init ();
2550 transit_init ();
2551}
2552
Chris Caputo228da422009-07-18 05:44:03 +00002553void
2554bgp_attr_finish (void)
2555{
2556 aspath_finish ();
2557 attrhash_finish ();
2558 community_finish ();
2559 ecommunity_finish ();
2560 cluster_finish ();
2561 transit_finish ();
2562}
2563
paul718e3742002-12-13 20:15:29 +00002564/* Make attribute packet. */
2565void
paula3845922003-10-18 01:30:50 +00002566bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2567 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002568{
2569 unsigned long cp;
2570 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002571 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002572 struct aspath *aspath;
2573
2574 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002575 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002576
2577 /* Place holder of length. */
2578 stream_putw (s, 0);
2579
2580 /* Origin attribute. */
2581 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2582 stream_putc (s, BGP_ATTR_ORIGIN);
2583 stream_putc (s, 1);
2584 stream_putc (s, attr->origin);
2585
2586 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002587
2588 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2589 stream_putc (s, BGP_ATTR_AS_PATH);
2590 aspath_lenp = stream_get_endp (s);
2591 stream_putw (s, 0);
2592
2593 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002594
2595 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002596 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2597 if(prefix != NULL
2598#ifdef HAVE_IPV6
2599 && prefix->family != AF_INET6
2600#endif /* HAVE_IPV6 */
2601 )
2602 {
2603 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2604 stream_putc (s, BGP_ATTR_NEXT_HOP);
2605 stream_putc (s, 4);
2606 stream_put_ipv4 (s, attr->nexthop.s_addr);
2607 }
paul718e3742002-12-13 20:15:29 +00002608
2609 /* MED attribute. */
2610 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2611 {
2612 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2613 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2614 stream_putc (s, 4);
2615 stream_putl (s, attr->med);
2616 }
2617
2618 /* Local preference. */
2619 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2620 {
2621 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2622 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2623 stream_putc (s, 4);
2624 stream_putl (s, attr->local_pref);
2625 }
2626
2627 /* Atomic aggregate. */
2628 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2629 {
2630 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2631 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2632 stream_putc (s, 0);
2633 }
2634
2635 /* Aggregator. */
2636 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2637 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002638 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002639 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2640 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002641 stream_putc (s, 8);
2642 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002643 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002644 }
2645
2646 /* Community attribute. */
2647 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2648 {
2649 if (attr->community->size * 4 > 255)
2650 {
2651 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2652 stream_putc (s, BGP_ATTR_COMMUNITIES);
2653 stream_putw (s, attr->community->size * 4);
2654 }
2655 else
2656 {
2657 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2658 stream_putc (s, BGP_ATTR_COMMUNITIES);
2659 stream_putc (s, attr->community->size * 4);
2660 }
2661 stream_put (s, attr->community->val, attr->community->size * 4);
2662 }
2663
paula3845922003-10-18 01:30:50 +00002664#ifdef HAVE_IPV6
2665 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002666 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2667 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002668 {
2669 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002670 struct attr_extra *attre = attr->extra;
2671
paula3845922003-10-18 01:30:50 +00002672 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2673 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002674 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002675
2676 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002677 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002678 stream_putw(s, AFI_IP6); /* AFI */
2679 stream_putc(s, SAFI_UNICAST); /* SAFI */
2680
2681 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002682 stream_putc(s, attre->mp_nexthop_len);
2683 stream_put(s, &attre->mp_nexthop_global, 16);
2684 if (attre->mp_nexthop_len == 32)
2685 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002686
2687 /* SNPA */
2688 stream_putc(s, 0);
2689
2690 /* Prefix */
2691 stream_put_prefix(s, prefix);
2692
2693 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002694 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002695 }
2696#endif /* HAVE_IPV6 */
2697
paul718e3742002-12-13 20:15:29 +00002698 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002699 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002700 stream_putw_at (s, cp, len);
2701}