blob: cbf2902d618c71932b053469d436ee71d859c9c4 [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 {
David Lamparterf47e5a12013-01-20 18:29:28 +01001363 if (!attr->aspath)
1364 return BGP_ATTR_PARSE_PROCEED;
1365
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001366 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001367 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001368 attr->aspath = aspath_intern (newpath);
1369 }
Paul Jakmab881c702010-11-23 16:35:42 +00001370 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001371}
1372
paul718e3742002-12-13 20:15:29 +00001373/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001374static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001375bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001376{
Paul Jakma835315b2012-01-18 12:28:30 +00001377 struct peer *const peer = args->peer;
1378 struct attr *const attr = args->attr;
1379 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001380
paul718e3742002-12-13 20:15:29 +00001381 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001382 {
1383 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001384 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001385 }
Paul Jakma0c466382010-12-05 17:17:26 +00001386
1387 attr->community =
1388 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1389
1390 /* XXX: fix community_parse to use stream API and remove this */
1391 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001392
Paul Jakma0c466382010-12-05 17:17:26 +00001393 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001394 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001395 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001396 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001397
paul718e3742002-12-13 20:15:29 +00001398 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1399
Paul Jakmab881c702010-11-23 16:35:42 +00001400 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001401}
1402
1403/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001404static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001405bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001406{
Paul Jakma835315b2012-01-18 12:28:30 +00001407 struct peer *const peer = args->peer;
1408 struct attr *const attr = args->attr;
1409 const bgp_size_t length = args->length;
1410
Denis Ovsienkod595b562011-09-30 15:08:54 +04001411 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001412 if (length != 4)
1413 {
1414 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1415
Paul Jakma835315b2012-01-18 12:28:30 +00001416 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001417 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001418 args->total);
paul718e3742002-12-13 20:15:29 +00001419 }
1420
Paul Jakmafb982c22007-05-04 20:15:47 +00001421 (bgp_attr_extra_get (attr))->originator_id.s_addr
1422 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001423
1424 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1425
Paul Jakmab881c702010-11-23 16:35:42 +00001426 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001427}
1428
1429/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001430static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001431bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001432{
Paul Jakma835315b2012-01-18 12:28:30 +00001433 struct peer *const peer = args->peer;
1434 struct attr *const attr = args->attr;
1435 const bgp_size_t length = args->length;
1436
paul718e3742002-12-13 20:15:29 +00001437 /* Check length. */
1438 if (length % 4)
1439 {
1440 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1441
Paul Jakma835315b2012-01-18 12:28:30 +00001442 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1443 args->total);
paul718e3742002-12-13 20:15:29 +00001444 }
1445
Paul Jakmafb982c22007-05-04 20:15:47 +00001446 (bgp_attr_extra_get (attr))->cluster
1447 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001448
1449 /* XXX: Fix cluster_parse to use stream API and then remove this */
1450 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001451
1452 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1453
Paul Jakmab881c702010-11-23 16:35:42 +00001454 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001455}
1456
1457/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001458int
Paul Jakma835315b2012-01-18 12:28:30 +00001459bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1460 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001461{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001462 afi_t afi;
1463 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001464 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001465 size_t start;
paul718e3742002-12-13 20:15:29 +00001466 int ret;
1467 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001468 struct peer *const peer = args->peer;
1469 struct attr *const attr = args->attr;
1470 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001471 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001472
paul718e3742002-12-13 20:15:29 +00001473 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001474 s = BGP_INPUT(peer);
1475 start = stream_get_getp(s);
1476
1477 /* safe to read statically sized header? */
1478#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001479#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001480 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001481 {
1482 zlog_info ("%s: %s sent invalid length, %lu",
1483 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001484 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001485 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001486
paul718e3742002-12-13 20:15:29 +00001487 /* Load AFI, SAFI. */
1488 afi = stream_getw (s);
1489 safi = stream_getc (s);
1490
1491 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001492 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001493
Paul Jakma03292802008-06-07 20:37:10 +00001494 if (LEN_LEFT < attre->mp_nexthop_len)
1495 {
1496 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1497 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001498 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001499 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001500
paul718e3742002-12-13 20:15:29 +00001501 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001502 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001503 {
1504 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001505 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001506 /* Probably needed for RFC 2283 */
1507 if (attr->nexthop.s_addr == 0)
1508 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001509 break;
1510 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001511 stream_getl (s); /* RD high */
1512 stream_getl (s); /* RD low */
1513 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001514 break;
1515#ifdef HAVE_IPV6
1516 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001517 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001518 break;
1519 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001520 stream_get (&attre->mp_nexthop_global, s, 16);
1521 stream_get (&attre->mp_nexthop_local, s, 16);
1522 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001523 {
1524 char buf1[INET6_ADDRSTRLEN];
1525 char buf2[INET6_ADDRSTRLEN];
1526
1527 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001528 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 +00001529 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001530 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001531 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001532 buf2, INET6_ADDRSTRLEN));
1533
Paul Jakmafb982c22007-05-04 20:15:47 +00001534 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001535 }
1536 break;
1537#endif /* HAVE_IPV6 */
1538 default:
Paul Jakma03292802008-06-07 20:37:10 +00001539 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1540 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001541 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001542 }
1543
Paul Jakma03292802008-06-07 20:37:10 +00001544 if (!LEN_LEFT)
1545 {
1546 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1547 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001548 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001549 }
paul718e3742002-12-13 20:15:29 +00001550
Paul Jakma6e4ab122007-04-10 19:36:48 +00001551 {
1552 u_char val;
1553 if ((val = stream_getc (s)))
1554 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1555 peer->host, val);
1556 }
1557
1558 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001559 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001560 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001561 {
1562 zlog_info ("%s: (%s) Failed to read NLRI",
1563 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001564 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001565 }
paul718e3742002-12-13 20:15:29 +00001566
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001567 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001568 {
1569 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001570 if (ret < 0)
1571 {
1572 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1573 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001574 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001575 }
paul718e3742002-12-13 20:15:29 +00001576 }
1577
1578 mp_update->afi = afi;
1579 mp_update->safi = safi;
1580 mp_update->nlri = stream_pnt (s);
1581 mp_update->length = nlri_len;
1582
paul9985f832005-02-09 15:51:56 +00001583 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001584
Paul Jakmab881c702010-11-23 16:35:42 +00001585 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001586#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001587}
1588
1589/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001590int
Paul Jakma835315b2012-01-18 12:28:30 +00001591bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001592 struct bgp_nlri *mp_withdraw)
1593{
1594 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001595 afi_t afi;
1596 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001597 u_int16_t withdraw_len;
1598 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001599 struct peer *const peer = args->peer;
1600 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001601
1602 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001603
1604#define BGP_MP_UNREACH_MIN_SIZE 3
1605 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001606 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001607
paul718e3742002-12-13 20:15:29 +00001608 afi = stream_getw (s);
1609 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001610
1611 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001612
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001613 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001614 {
1615 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1616 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001617 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001618 }
1619
1620 mp_withdraw->afi = afi;
1621 mp_withdraw->safi = safi;
1622 mp_withdraw->nlri = stream_pnt (s);
1623 mp_withdraw->length = withdraw_len;
1624
paul9985f832005-02-09 15:51:56 +00001625 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001626
Paul Jakmab881c702010-11-23 16:35:42 +00001627 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001628}
1629
1630/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001631static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001632bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001633{
Paul Jakma835315b2012-01-18 12:28:30 +00001634 struct peer *const peer = args->peer;
1635 struct attr *const attr = args->attr;
1636 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001637
paul718e3742002-12-13 20:15:29 +00001638 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001639 {
1640 if (attr->extra)
1641 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001642 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001643 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001644 }
Paul Jakma0c466382010-12-05 17:17:26 +00001645
1646 (bgp_attr_extra_get (attr))->ecommunity =
1647 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1648 /* XXX: fix ecommunity_parse to use stream API */
1649 stream_forward_getp (peer->ibuf, length);
1650
1651 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001652 return bgp_attr_malformed (args,
1653 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1654 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001655
paul718e3742002-12-13 20:15:29 +00001656 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1657
Paul Jakmab881c702010-11-23 16:35:42 +00001658 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001659}
1660
1661/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001662static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001663bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001664{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001665 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001666 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001667 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001668 struct peer *const peer = args->peer;
1669 struct attr *const attr = args->attr;
1670 u_char *const startp = args->startp;
1671 const u_char type = args->type;
1672 const u_char flag = args->flags;
1673 const bgp_size_t length = args->length;
1674
paul718e3742002-12-13 20:15:29 +00001675
hassof4184462005-02-01 20:13:16 +00001676 if (BGP_DEBUG (normal, NORMAL))
1677 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1678 peer->host, type, length);
1679
paul718e3742002-12-13 20:15:29 +00001680 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001681 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001682 "Unknown attribute type %d length %d is received", type, length);
1683
1684 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001685 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001686
paul718e3742002-12-13 20:15:29 +00001687 /* If any of the mandatory well-known attributes are not recognized,
1688 then the Error Subcode is set to Unrecognized Well-known
1689 Attribute. The Data field contains the unrecognized attribute
1690 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001691 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001692 {
Paul Jakma835315b2012-01-18 12:28:30 +00001693 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001694 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001695 args->total);
paul718e3742002-12-13 20:15:29 +00001696 }
1697
1698 /* Unrecognized non-transitive optional attributes must be quietly
1699 ignored and not passed along to other BGP peers. */
1700 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001701 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001702
1703 /* If a path with recognized transitive optional attribute is
1704 accepted and passed along to other BGP peers and the Partial bit
1705 in the Attribute Flags octet is set to 1 by some previous AS, it
1706 is not set back to 0 by the current AS. */
1707 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1708
1709 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001710 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001711 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001712
Paul Jakmafb982c22007-05-04 20:15:47 +00001713 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001714
1715 if (transit->val)
1716 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1717 transit->length + total);
1718 else
1719 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1720
1721 memcpy (transit->val + transit->length, startp, total);
1722 transit->length += total;
1723
Paul Jakmab881c702010-11-23 16:35:42 +00001724 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001725}
1726
1727/* Read attribute of update packet. This function is called from
Andrew Certain8b366b92012-11-07 23:50:08 +00001728 bgp_update_receive() in bgp_packet.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001729bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001730bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1731 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1732{
1733 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001734 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001735 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001736 bgp_size_t length;
1737 u_char *startp, *endp;
1738 u_char *attr_endp;
1739 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001740 /* we need the as4_path only until we have synthesized the as_path with it */
1741 /* same goes for as4_aggregator */
1742 struct aspath *as4_path = NULL;
1743 as_t as4_aggregator = 0;
1744 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001745
1746 /* Initialize bitmap. */
1747 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1748
1749 /* End pointer of BGP attribute. */
1750 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001751
paul718e3742002-12-13 20:15:29 +00001752 /* Get attributes to the end of attribute length. */
1753 while (BGP_INPUT_PNT (peer) < endp)
1754 {
1755 /* Check remaining length check.*/
1756 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1757 {
gdtc29fdba2004-12-09 14:46:46 +00001758 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001759 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001760 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001761 peer->host,
1762 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001763
1764 bgp_notify_send (peer,
1765 BGP_NOTIFY_UPDATE_ERR,
1766 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001767 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001768 }
1769
1770 /* Fetch attribute flag and type. */
1771 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001772 /* "The lower-order four bits of the Attribute Flags octet are
1773 unused. They MUST be zero when sent and MUST be ignored when
1774 received." */
1775 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001776 type = stream_getc (BGP_INPUT (peer));
1777
Paul Jakma370b64a2007-12-22 16:49:52 +00001778 /* Check whether Extended-Length applies and is in bounds */
1779 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1780 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1781 {
1782 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001783 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001784 peer->host,
1785 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1786
1787 bgp_notify_send (peer,
1788 BGP_NOTIFY_UPDATE_ERR,
1789 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001790 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001791 }
Paul Jakma835315b2012-01-18 12:28:30 +00001792
paul718e3742002-12-13 20:15:29 +00001793 /* Check extended attribue length bit. */
1794 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1795 length = stream_getw (BGP_INPUT (peer));
1796 else
1797 length = stream_getc (BGP_INPUT (peer));
1798
1799 /* If any attribute appears more than once in the UPDATE
1800 message, then the Error Subcode is set to Malformed Attribute
1801 List. */
1802
1803 if (CHECK_BITMAP (seen, type))
1804 {
1805 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001806 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001807 peer->host, type);
1808
1809 bgp_notify_send (peer,
1810 BGP_NOTIFY_UPDATE_ERR,
1811 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001812 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001813 }
1814
1815 /* Set type to bitmap to check duplicate attribute. `type' is
1816 unsigned char so it never overflow bitmap range. */
1817
1818 SET_BITMAP (seen, type);
1819
1820 /* Overflow check. */
1821 attr_endp = BGP_INPUT_PNT (peer) + length;
1822
1823 if (attr_endp > endp)
1824 {
1825 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001826 "%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 +00001827 bgp_notify_send (peer,
1828 BGP_NOTIFY_UPDATE_ERR,
1829 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001830 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001831 }
Paul Jakma835315b2012-01-18 12:28:30 +00001832
1833 struct bgp_attr_parser_args attr_args = {
1834 .peer = peer,
1835 .length = length,
1836 .attr = attr,
1837 .type = type,
1838 .flags = flag,
1839 .startp = startp,
1840 .total = attr_endp - startp,
1841 };
1842
1843
1844 /* If any recognized attribute has Attribute Flags that conflict
1845 with the Attribute Type Code, then the Error Subcode is set to
1846 Attribute Flags Error. The Data field contains the erroneous
1847 attribute (type, length and value). */
1848 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001849 {
1850 bgp_attr_parse_ret_t ret;
1851 ret = bgp_attr_malformed (&attr_args,
1852 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1853 attr_args.total);
1854 if (ret == BGP_ATTR_PARSE_PROCEED)
1855 continue;
1856 return ret;
1857 }
paul718e3742002-12-13 20:15:29 +00001858
1859 /* OK check attribute and store it's value. */
1860 switch (type)
1861 {
1862 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001863 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001864 break;
1865 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001866 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001867 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001868 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001869 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001870 break;
paul718e3742002-12-13 20:15:29 +00001871 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001872 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001873 break;
1874 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001875 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001876 break;
1877 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001878 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001879 break;
1880 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001881 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001882 break;
1883 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001884 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001885 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001886 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001887 ret = bgp_attr_as4_aggregator (&attr_args,
1888 &as4_aggregator,
1889 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001890 break;
paul718e3742002-12-13 20:15:29 +00001891 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001892 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001893 break;
1894 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001895 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001896 break;
1897 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001898 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001899 break;
1900 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001901 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001902 break;
1903 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001904 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001905 break;
1906 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001907 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001908 break;
1909 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001910 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001911 break;
1912 }
Paul Jakmab881c702010-11-23 16:35:42 +00001913
1914 /* If hard error occured immediately return to the caller. */
1915 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001916 {
1917 zlog (peer->log, LOG_WARNING,
1918 "%s: Attribute %s, parse error",
1919 peer->host,
1920 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001921 bgp_notify_send (peer,
1922 BGP_NOTIFY_UPDATE_ERR,
1923 BGP_NOTIFY_UPDATE_MAL_ATTR);
1924 if (as4_path)
1925 aspath_unintern (&as4_path);
1926 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001927 }
Paul Jakmab881c702010-11-23 16:35:42 +00001928 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1929 {
1930
1931 zlog (peer->log, LOG_WARNING,
1932 "%s: Attribute %s, parse error - treating as withdrawal",
1933 peer->host,
1934 LOOKUP (attr_str, type));
1935 if (as4_path)
1936 aspath_unintern (&as4_path);
1937 return ret;
1938 }
1939
paul718e3742002-12-13 20:15:29 +00001940 /* Check the fetched length. */
1941 if (BGP_INPUT_PNT (peer) != attr_endp)
1942 {
1943 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001944 "%s: BGP attribute %s, fetch error",
1945 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001946 bgp_notify_send (peer,
1947 BGP_NOTIFY_UPDATE_ERR,
1948 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001949 if (as4_path)
1950 aspath_unintern (&as4_path);
1951 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001952 }
1953 }
1954
1955 /* Check final read pointer is same as end pointer. */
1956 if (BGP_INPUT_PNT (peer) != endp)
1957 {
1958 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001959 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001960 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001961 bgp_notify_send (peer,
1962 BGP_NOTIFY_UPDATE_ERR,
1963 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001964 if (as4_path)
1965 aspath_unintern (&as4_path);
1966 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001967 }
1968
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001969 /*
1970 * At this place we can see whether we got AS4_PATH and/or
1971 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1972 * We can not do this before we've read all attributes because
1973 * the as4 handling does not say whether AS4_PATH has to be sent
1974 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1975 * in relationship to AGGREGATOR.
1976 * So, to be defensive, we are not relying on any order and read
1977 * all attributes first, including these 32bit ones, and now,
1978 * afterwards, we look what and if something is to be done for as4.
1979 */
Paul Jakma835315b2012-01-18 12:28:30 +00001980 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001981 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001982 {
1983 if (as4_path)
1984 aspath_unintern (&as4_path);
1985 return BGP_ATTR_PARSE_ERROR;
1986 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001987
1988 /* At this stage, we have done all fiddling with as4, and the
1989 * resulting info is in attr->aggregator resp. attr->aspath
1990 * so we can chuck as4_aggregator and as4_path alltogether in
1991 * order to save memory
1992 */
Paul Jakmab881c702010-11-23 16:35:42 +00001993 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001994 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001995 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001996 /* The flag that we got this is still there, but that does not
1997 * do any trouble
1998 */
1999 }
2000 /*
2001 * The "rest" of the code does nothing with as4_aggregator.
2002 * there is no memory attached specifically which is not part
2003 * of the attr.
2004 * so ignoring just means do nothing.
2005 */
2006 /*
2007 * Finally do the checks on the aspath we did not do yet
2008 * because we waited for a potentially synthesized aspath.
2009 */
Paul Jakmab881c702010-11-23 16:35:42 +00002010 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002011 {
Paul Jakma835315b2012-01-18 12:28:30 +00002012 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00002013 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002014 return ret;
2015 }
2016
paul718e3742002-12-13 20:15:29 +00002017 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002018 if (attr->extra && attr->extra->transit)
2019 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002020
Paul Jakmab881c702010-11-23 16:35:42 +00002021 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002022}
2023
2024/* Well-known attribute check. */
2025int
2026bgp_attr_check (struct peer *peer, struct attr *attr)
2027{
2028 u_char type = 0;
2029
2030 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2031 type = BGP_ATTR_ORIGIN;
2032
2033 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2034 type = BGP_ATTR_AS_PATH;
2035
2036 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2037 type = BGP_ATTR_NEXT_HOP;
2038
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002039 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002040 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2041 type = BGP_ATTR_LOCAL_PREF;
2042
2043 if (type)
2044 {
2045 zlog (peer->log, LOG_WARNING,
2046 "%s Missing well-known attribute %d.",
2047 peer->host, type);
2048 bgp_notify_send_with_data (peer,
2049 BGP_NOTIFY_UPDATE_ERR,
2050 BGP_NOTIFY_UPDATE_MISS_ATTR,
2051 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002052 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002053 }
Paul Jakmab881c702010-11-23 16:35:42 +00002054 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002055}
2056
2057int stream_put_prefix (struct stream *, struct prefix *);
2058
2059/* Make attribute packet. */
2060bgp_size_t
2061bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2062 struct stream *s, struct attr *attr, struct prefix *p,
2063 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002064 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002065{
paulfe69a502005-09-10 16:55:02 +00002066 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002067 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002068 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002069 int send_as4_path = 0;
2070 int send_as4_aggregator = 0;
2071 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002072
2073 if (! bgp)
2074 bgp = bgp_get_default ();
2075
2076 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002077 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002078
2079 /* Origin attribute. */
2080 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2081 stream_putc (s, BGP_ATTR_ORIGIN);
2082 stream_putc (s, 1);
2083 stream_putc (s, attr->origin);
2084
2085 /* AS path attribute. */
2086
2087 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002088 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002089 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002090 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002091 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002092 {
2093 aspath = aspath_dup (attr->aspath);
2094
2095 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2096 {
2097 /* Strip the confed info, and then stuff our path CONFED_ID
2098 on the front */
2099 aspath = aspath_delete_confed_seq (aspath);
2100 aspath = aspath_add_seq (aspath, bgp->confed_id);
2101 }
2102 else
2103 {
Andrew Certain9d3f9702012-11-07 23:50:07 +00002104 if (peer->change_local_as) {
2105 /* If replace-as is specified, we only use the change_local_as when
2106 advertising routes. */
2107 if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
2108 aspath = aspath_add_seq (aspath, peer->local_as);
2109 }
paul718e3742002-12-13 20:15:29 +00002110 aspath = aspath_add_seq (aspath, peer->change_local_as);
Andrew Certain9d3f9702012-11-07 23:50:07 +00002111 } else {
2112 aspath = aspath_add_seq (aspath, peer->local_as);
2113 }
paul718e3742002-12-13 20:15:29 +00002114 }
2115 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002116 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002117 {
2118 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2119 aspath = aspath_dup (attr->aspath);
2120 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2121 }
2122 else
2123 aspath = attr->aspath;
2124
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002125 /* If peer is not AS4 capable, then:
2126 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2127 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2128 * types are in it (i.e. exclude them if they are there)
2129 * AND do this only if there is at least one asnum > 65535 in the path!
2130 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2131 * all ASnums > 65535 to BGP_AS_TRANS
2132 */
paul718e3742002-12-13 20:15:29 +00002133
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002134 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2135 stream_putc (s, BGP_ATTR_AS_PATH);
2136 aspath_sizep = stream_get_endp (s);
2137 stream_putw (s, 0);
2138 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2139
2140 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2141 * in the path
2142 */
2143 if (!use32bit && aspath_has_as4 (aspath))
2144 send_as4_path = 1; /* we'll do this later, at the correct place */
2145
paul718e3742002-12-13 20:15:29 +00002146 /* Nexthop attribute. */
2147 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2148 {
2149 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2150 stream_putc (s, BGP_ATTR_NEXT_HOP);
2151 stream_putc (s, 4);
2152 if (safi == SAFI_MPLS_VPN)
2153 {
2154 if (attr->nexthop.s_addr == 0)
2155 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2156 else
2157 stream_put_ipv4 (s, attr->nexthop.s_addr);
2158 }
2159 else
2160 stream_put_ipv4 (s, attr->nexthop.s_addr);
2161 }
2162
2163 /* MED attribute. */
2164 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2165 {
2166 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2167 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2168 stream_putc (s, 4);
2169 stream_putl (s, attr->med);
2170 }
2171
2172 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002173 if (peer->sort == BGP_PEER_IBGP ||
2174 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002175 {
2176 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2177 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2178 stream_putc (s, 4);
2179 stream_putl (s, attr->local_pref);
2180 }
2181
2182 /* Atomic aggregate. */
2183 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2184 {
2185 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2186 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2187 stream_putc (s, 0);
2188 }
2189
2190 /* Aggregator. */
2191 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2192 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002193 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002194
2195 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002196 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2197 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002198
2199 if (use32bit)
2200 {
2201 /* AS4 capable peer */
2202 stream_putc (s, 8);
2203 stream_putl (s, attr->extra->aggregator_as);
2204 }
2205 else
2206 {
2207 /* 2-byte AS peer */
2208 stream_putc (s, 6);
2209
2210 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2211 if ( attr->extra->aggregator_as > 65535 )
2212 {
2213 stream_putw (s, BGP_AS_TRANS);
2214
2215 /* we have to send AS4_AGGREGATOR, too.
2216 * we'll do that later in order to send attributes in ascending
2217 * order.
2218 */
2219 send_as4_aggregator = 1;
2220 }
2221 else
2222 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2223 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002224 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002225 }
2226
2227 /* Community attribute. */
2228 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2229 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2230 {
2231 if (attr->community->size * 4 > 255)
2232 {
2233 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2234 stream_putc (s, BGP_ATTR_COMMUNITIES);
2235 stream_putw (s, attr->community->size * 4);
2236 }
2237 else
2238 {
2239 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2240 stream_putc (s, BGP_ATTR_COMMUNITIES);
2241 stream_putc (s, attr->community->size * 4);
2242 }
2243 stream_put (s, attr->community->val, attr->community->size * 4);
2244 }
2245
2246 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002247 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002248 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002249 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002250 {
2251 /* Originator ID. */
2252 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2253 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2254 stream_putc (s, 4);
2255
2256 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002257 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002258 else
2259 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002260
2261 /* Cluster list. */
2262 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2263 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2264
Paul Jakma9eda90c2007-08-30 13:36:17 +00002265 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002266 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002267 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002268 /* If this peer configuration's parent BGP has cluster_id. */
2269 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2270 stream_put_in_addr (s, &bgp->cluster_id);
2271 else
2272 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002273 stream_put (s, attr->extra->cluster->list,
2274 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002275 }
2276 else
2277 {
2278 stream_putc (s, 4);
2279 /* If this peer configuration's parent BGP has cluster_id. */
2280 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2281 stream_put_in_addr (s, &bgp->cluster_id);
2282 else
2283 stream_put_in_addr (s, &bgp->router_id);
2284 }
2285 }
2286
2287#ifdef HAVE_IPV6
2288 /* If p is IPv6 address put it into attribute. */
2289 if (p->family == AF_INET6)
2290 {
2291 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002292 struct attr_extra *attre = attr->extra;
2293
2294 assert (attr->extra);
2295
paul718e3742002-12-13 20:15:29 +00002296 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2297 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002298 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002299 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002300 stream_putw (s, AFI_IP6); /* AFI */
2301 stream_putc (s, safi); /* SAFI */
2302
Paul Jakmafb982c22007-05-04 20:15:47 +00002303 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002304
Paul Jakmafb982c22007-05-04 20:15:47 +00002305 if (attre->mp_nexthop_len == 16)
2306 stream_put (s, &attre->mp_nexthop_global, 16);
2307 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002308 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002309 stream_put (s, &attre->mp_nexthop_global, 16);
2310 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002311 }
2312
2313 /* SNPA */
2314 stream_putc (s, 0);
2315
paul718e3742002-12-13 20:15:29 +00002316 /* Prefix write. */
2317 stream_put_prefix (s, p);
2318
2319 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002320 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002321 }
2322#endif /* HAVE_IPV6 */
2323
2324 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2325 {
2326 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002327
2328 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2329 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002330 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002331 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002332 stream_putw (s, AFI_IP); /* AFI */
2333 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2334
2335 stream_putc (s, 4);
2336 stream_put_ipv4 (s, attr->nexthop.s_addr);
2337
2338 /* SNPA */
2339 stream_putc (s, 0);
2340
paul718e3742002-12-13 20:15:29 +00002341 /* Prefix write. */
2342 stream_put_prefix (s, p);
2343
2344 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002345 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002346 }
2347
2348 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2349 {
2350 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002351
2352 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2353 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002354 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002355 stream_putc (s, 0); /* Length of this attribute. */
2356 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002357 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002358
2359 stream_putc (s, 12);
2360 stream_putl (s, 0);
2361 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002362 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002363
2364 /* SNPA */
2365 stream_putc (s, 0);
2366
paul718e3742002-12-13 20:15:29 +00002367 /* Tag, RD, Prefix write. */
2368 stream_putc (s, p->prefixlen + 88);
2369 stream_put (s, tag, 3);
2370 stream_put (s, prd->val, 8);
2371 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2372
2373 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002374 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002375 }
2376
2377 /* Extended Communities attribute. */
2378 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2379 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2380 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002381 struct attr_extra *attre = attr->extra;
2382
2383 assert (attre);
2384
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002385 if (peer->sort == BGP_PEER_IBGP
2386 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002387 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002388 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002389 {
2390 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2391 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002392 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002393 }
2394 else
2395 {
2396 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2397 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002398 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002399 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002400 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002401 }
2402 else
2403 {
paul5228ad22004-06-04 17:58:18 +00002404 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002405 int tbit;
2406 int ecom_tr_size = 0;
2407 int i;
2408
Paul Jakmafb982c22007-05-04 20:15:47 +00002409 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002410 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002412 tbit = *pnt;
2413
2414 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2415 continue;
2416
2417 ecom_tr_size++;
2418 }
2419
2420 if (ecom_tr_size)
2421 {
2422 if (ecom_tr_size * 8 > 255)
2423 {
2424 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2425 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2426 stream_putw (s, ecom_tr_size * 8);
2427 }
2428 else
2429 {
2430 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2431 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2432 stream_putc (s, ecom_tr_size * 8);
2433 }
2434
Paul Jakmafb982c22007-05-04 20:15:47 +00002435 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002436 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002437 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002438 tbit = *pnt;
2439
2440 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2441 continue;
2442
2443 stream_put (s, pnt, 8);
2444 }
2445 }
paul718e3742002-12-13 20:15:29 +00002446 }
paul718e3742002-12-13 20:15:29 +00002447 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002448
2449 if ( send_as4_path )
2450 {
2451 /* If the peer is NOT As4 capable, AND */
2452 /* there are ASnums > 65535 in path THEN
2453 * give out AS4_PATH */
2454
2455 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2456 * path segments!
2457 * Hm, I wonder... confederation things *should* only be at
2458 * the beginning of an aspath, right? Then we should use
2459 * aspath_delete_confed_seq for this, because it is already
2460 * there! (JK)
2461 * Folks, talk to me: what is reasonable here!?
2462 */
2463 aspath = aspath_delete_confed_seq (aspath);
2464
2465 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2466 stream_putc (s, BGP_ATTR_AS4_PATH);
2467 aspath_sizep = stream_get_endp (s);
2468 stream_putw (s, 0);
2469 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2470 }
2471
2472 if (aspath != attr->aspath)
2473 aspath_free (aspath);
2474
2475 if ( send_as4_aggregator )
2476 {
2477 assert (attr->extra);
2478
2479 /* send AS4_AGGREGATOR, at this place */
2480 /* this section of code moved here in order to ensure the correct
2481 * *ascending* order of attributes
2482 */
2483 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2484 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2485 stream_putc (s, 8);
2486 stream_putl (s, attr->extra->aggregator_as);
2487 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2488 }
Paul Jakma41367172007-08-06 15:24:51 +00002489
paul718e3742002-12-13 20:15:29 +00002490 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002491 if (attr->extra && attr->extra->transit)
2492 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002493
2494 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002495 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002496}
2497
2498bgp_size_t
2499bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2500 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002501 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002502{
2503 unsigned long cp;
2504 unsigned long attrlen_pnt;
2505 bgp_size_t size;
2506
paul9985f832005-02-09 15:51:56 +00002507 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002508
2509 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2510 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2511
paul9985f832005-02-09 15:51:56 +00002512 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002513 stream_putc (s, 0); /* Length of this attribute. */
2514
2515 stream_putw (s, family2afi (p->family));
2516
2517 if (safi == SAFI_MPLS_VPN)
2518 {
2519 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002520 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002521
2522 /* prefix. */
2523 stream_putc (s, p->prefixlen + 88);
2524 stream_put (s, tag, 3);
2525 stream_put (s, prd->val, 8);
2526 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2527 }
2528 else
2529 {
2530 /* SAFI */
2531 stream_putc (s, safi);
2532
2533 /* prefix */
2534 stream_put_prefix (s, p);
2535 }
2536
2537 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002538 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002539 stream_putc_at (s, attrlen_pnt, size);
2540
paul9985f832005-02-09 15:51:56 +00002541 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002542}
2543
2544/* Initialization of attribute. */
2545void
paulfe69a502005-09-10 16:55:02 +00002546bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002547{
paul718e3742002-12-13 20:15:29 +00002548 aspath_init ();
2549 attrhash_init ();
2550 community_init ();
2551 ecommunity_init ();
2552 cluster_init ();
2553 transit_init ();
2554}
2555
Chris Caputo228da422009-07-18 05:44:03 +00002556void
2557bgp_attr_finish (void)
2558{
2559 aspath_finish ();
2560 attrhash_finish ();
2561 community_finish ();
2562 ecommunity_finish ();
2563 cluster_finish ();
2564 transit_finish ();
2565}
2566
paul718e3742002-12-13 20:15:29 +00002567/* Make attribute packet. */
2568void
paula3845922003-10-18 01:30:50 +00002569bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2570 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002571{
2572 unsigned long cp;
2573 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002574 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002575 struct aspath *aspath;
2576
2577 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002578 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002579
2580 /* Place holder of length. */
2581 stream_putw (s, 0);
2582
2583 /* Origin attribute. */
2584 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2585 stream_putc (s, BGP_ATTR_ORIGIN);
2586 stream_putc (s, 1);
2587 stream_putc (s, attr->origin);
2588
2589 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002590
2591 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2592 stream_putc (s, BGP_ATTR_AS_PATH);
2593 aspath_lenp = stream_get_endp (s);
2594 stream_putw (s, 0);
2595
2596 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002597
2598 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002599 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2600 if(prefix != NULL
2601#ifdef HAVE_IPV6
2602 && prefix->family != AF_INET6
2603#endif /* HAVE_IPV6 */
2604 )
2605 {
2606 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2607 stream_putc (s, BGP_ATTR_NEXT_HOP);
2608 stream_putc (s, 4);
2609 stream_put_ipv4 (s, attr->nexthop.s_addr);
2610 }
paul718e3742002-12-13 20:15:29 +00002611
2612 /* MED attribute. */
2613 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2614 {
2615 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2616 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2617 stream_putc (s, 4);
2618 stream_putl (s, attr->med);
2619 }
2620
2621 /* Local preference. */
2622 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2623 {
2624 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2625 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2626 stream_putc (s, 4);
2627 stream_putl (s, attr->local_pref);
2628 }
2629
2630 /* Atomic aggregate. */
2631 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2632 {
2633 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2634 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2635 stream_putc (s, 0);
2636 }
2637
2638 /* Aggregator. */
2639 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2640 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002641 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002642 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2643 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002644 stream_putc (s, 8);
2645 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002646 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002647 }
2648
2649 /* Community attribute. */
2650 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2651 {
2652 if (attr->community->size * 4 > 255)
2653 {
2654 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2655 stream_putc (s, BGP_ATTR_COMMUNITIES);
2656 stream_putw (s, attr->community->size * 4);
2657 }
2658 else
2659 {
2660 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2661 stream_putc (s, BGP_ATTR_COMMUNITIES);
2662 stream_putc (s, attr->community->size * 4);
2663 }
2664 stream_put (s, attr->community->val, attr->community->size * 4);
2665 }
2666
paula3845922003-10-18 01:30:50 +00002667#ifdef HAVE_IPV6
2668 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002669 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2670 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002671 {
2672 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002673 struct attr_extra *attre = attr->extra;
2674
paula3845922003-10-18 01:30:50 +00002675 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2676 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002677 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002678
2679 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002680 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002681 stream_putw(s, AFI_IP6); /* AFI */
2682 stream_putc(s, SAFI_UNICAST); /* SAFI */
2683
2684 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002685 stream_putc(s, attre->mp_nexthop_len);
2686 stream_put(s, &attre->mp_nexthop_global, 16);
2687 if (attre->mp_nexthop_len == 32)
2688 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002689
2690 /* SNPA */
2691 stream_putc(s, 0);
2692
2693 /* Prefix */
2694 stream_put_prefix(s, prefix);
2695
2696 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002697 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002698 }
2699#endif /* HAVE_IPV6 */
2700
paul718e3742002-12-13 20:15:29 +00002701 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002702 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002703 stream_putw_at (s, cp, len);
2704}