blob: cdc99ab3ac60ed8ddb1b3d1c655bb5334c707f58 [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;
324 if (orig->extra)
325 {
Jorge Boncompte [DTI2]558d1fe2012-05-07 16:53:05 +0000326 /* if caller provided attr_extra space use it */
327 if (! extra)
328 new->extra = bgp_attr_extra_new();
Paul Jakmafb982c22007-05-04 20:15:47 +0000329 *new->extra = *orig->extra;
330 }
331}
332
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000333unsigned long int
334attr_count (void)
335{
336 return attrhash->count;
337}
338
339unsigned long int
340attr_unknown_count (void)
341{
342 return transit_hash->count;
343}
344
paul718e3742002-12-13 20:15:29 +0000345unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000346attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000347{
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000348 const struct attr *attr = (struct attr *) p;
349 const struct attr_extra *extra = attr->extra;
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700350 uint32_t key = 0;
351#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000352
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700353 MIX(attr->origin);
354 MIX(attr->nexthop.s_addr);
355 MIX(attr->med);
356 MIX(attr->local_pref);
357
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000362
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000363 if (extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000364 {
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000365 MIX(extra->aggregator_as);
366 MIX(extra->aggregator_addr.s_addr);
367 MIX(extra->weight);
368 MIX(extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000369 }
370
paul718e3742002-12-13 20:15:29 +0000371 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700372 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000373 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700374 MIX(community_hash_make (attr->community));
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 if (extra->ecommunity)
379 MIX(ecommunity_hash_make (extra->ecommunity));
380 if (extra->cluster)
381 MIX(cluster_hash_key_make (extra->cluster));
382 if (extra->transit)
383 MIX(transit_hash_key_make (extra->transit));
paul718e3742002-12-13 20:15:29 +0000384
385#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]7fb0cd82012-05-07 16:52:58 +0000386 MIX(extra->mp_nexthop_len);
387 key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
388 key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000389#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000390 }
paul718e3742002-12-13 20:15:29 +0000391
392 return key;
393}
394
395int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100396attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000397{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100398 const struct attr * attr1 = p1;
399 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000400
paul718e3742002-12-13 20:15:29 +0000401 if (attr1->flag == attr2->flag
402 && attr1->origin == attr2->origin
403 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000404 && attr1->aspath == attr2->aspath
405 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000406 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000407 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000408 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100409 const struct attr_extra *ae1 = attr1->extra;
410 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000411
412 if (ae1 && ae2
413 && ae1->aggregator_as == ae2->aggregator_as
414 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
415 && ae1->weight == ae2->weight
416#ifdef HAVE_IPV6
417 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
418 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
419 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
420#endif /* HAVE_IPV6 */
421 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
422 && ae1->ecommunity == ae2->ecommunity
423 && ae1->cluster == ae2->cluster
424 && ae1->transit == ae2->transit)
425 return 1;
426 else if (ae1 || ae2)
427 return 0;
428 /* neither attribute has extra attributes, so they're same */
429 return 1;
430 }
paul718e3742002-12-13 20:15:29 +0000431 else
432 return 0;
433}
434
paul94f2b392005-06-28 12:44:16 +0000435static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100436attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000437{
438 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
439}
440
paul94f2b392005-06-28 12:44:16 +0000441static void
Chris Caputo228da422009-07-18 05:44:03 +0000442attrhash_finish (void)
443{
444 hash_free (attrhash);
445 attrhash = NULL;
446}
447
448static void
paul718e3742002-12-13 20:15:29 +0000449attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
450{
451 struct attr *attr = backet->data;
452
453 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
454 inet_ntoa (attr->nexthop), VTY_NEWLINE);
455}
456
457void
458attr_show_all (struct vty *vty)
459{
460 hash_iterate (attrhash,
461 (void (*)(struct hash_backet *, void *))
462 attr_show_all_iterator,
463 vty);
464}
465
paul94f2b392005-06-28 12:44:16 +0000466static void *
Paul Jakma923de652007-04-29 18:25:17 +0000467bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000468{
Paul Jakma923de652007-04-29 18:25:17 +0000469 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000470 struct attr *attr;
471
472 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
473 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000474 if (val->extra)
475 {
476 attr->extra = bgp_attr_extra_new ();
477 *attr->extra = *val->extra;
478 }
paul718e3742002-12-13 20:15:29 +0000479 attr->refcnt = 0;
480 return attr;
481}
482
483/* Internet argument attribute. */
484struct attr *
485bgp_attr_intern (struct attr *attr)
486{
487 struct attr *find;
488
489 /* Intern referenced strucutre. */
490 if (attr->aspath)
491 {
492 if (! attr->aspath->refcnt)
493 attr->aspath = aspath_intern (attr->aspath);
494 else
495 attr->aspath->refcnt++;
496 }
497 if (attr->community)
498 {
499 if (! attr->community->refcnt)
500 attr->community = community_intern (attr->community);
501 else
502 attr->community->refcnt++;
503 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000504 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000505 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000506 struct attr_extra *attre = attr->extra;
507
508 if (attre->ecommunity)
509 {
510 if (! attre->ecommunity->refcnt)
511 attre->ecommunity = ecommunity_intern (attre->ecommunity);
512 else
513 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000514
Paul Jakmafb982c22007-05-04 20:15:47 +0000515 }
516 if (attre->cluster)
517 {
518 if (! attre->cluster->refcnt)
519 attre->cluster = cluster_intern (attre->cluster);
520 else
521 attre->cluster->refcnt++;
522 }
523 if (attre->transit)
524 {
525 if (! attre->transit->refcnt)
526 attre->transit = transit_intern (attre->transit);
527 else
528 attre->transit->refcnt++;
529 }
paul718e3742002-12-13 20:15:29 +0000530 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000531
paul718e3742002-12-13 20:15:29 +0000532 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
533 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000534
paul718e3742002-12-13 20:15:29 +0000535 return find;
536}
537
Paul Jakma03e214c2007-04-29 18:31:07 +0000538
paul718e3742002-12-13 20:15:29 +0000539/* Make network statement's attribute. */
540struct attr *
541bgp_attr_default_set (struct attr *attr, u_char origin)
542{
543 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000544 bgp_attr_extra_get (attr);
545
paul718e3742002-12-13 20:15:29 +0000546 attr->origin = origin;
547 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
548 attr->aspath = aspath_empty ();
549 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000550 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000551 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
552#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000553 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000554#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000555
paul718e3742002-12-13 20:15:29 +0000556 return attr;
557}
558
Paul Jakma03e214c2007-04-29 18:31:07 +0000559
paul718e3742002-12-13 20:15:29 +0000560/* Make network statement's attribute. */
561struct attr *
562bgp_attr_default_intern (u_char origin)
563{
564 struct attr attr;
565 struct attr *new;
Jorge Boncompte [DTI2]e16a4132012-05-07 16:52:57 +0000566
Paul Jakma03e214c2007-04-29 18:31:07 +0000567 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000568
569 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000570 bgp_attr_extra_free (&attr);
571
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000572 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000573 return new;
574}
575
576struct attr *
577bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
578 struct aspath *aspath,
579 struct community *community, int as_set)
580{
581 struct attr attr;
582 struct attr *new;
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000583 struct attr_extra attre;
paul718e3742002-12-13 20:15:29 +0000584
585 memset (&attr, 0, sizeof (struct attr));
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000586 memset (&attre, 0, sizeof (struct attr_extra));
587 attr.extra = &attre;
588
paul718e3742002-12-13 20:15:29 +0000589 /* Origin attribute. */
590 attr.origin = origin;
591 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
592
593 /* AS path attribute. */
594 if (aspath)
595 attr.aspath = aspath_intern (aspath);
596 else
597 attr.aspath = aspath_empty ();
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
599
600 /* Next hop attribute. */
601 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
602
603 if (community)
604 {
605 attr.community = community;
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
607 }
608
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000609 attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000610#ifdef HAVE_IPV6
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000611 attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000612#endif
613 if (! as_set)
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
615 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
616 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000617 attre.aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000618 else
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000619 attre.aggregator_as = bgp->as;
620 attre.aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000621
622 new = bgp_attr_intern (&attr);
Jorge Boncompte [DTI2]938ef3a2012-05-07 16:52:59 +0000623
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000624 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000625 return new;
626}
627
Paul Jakmab881c702010-11-23 16:35:42 +0000628/* Unintern just the sub-components of the attr, but not the attr */
629void
630bgp_attr_unintern_sub (struct attr *attr)
631{
632 /* aspath refcount shoud be decrement. */
633 if (attr->aspath)
634 aspath_unintern (&attr->aspath);
635 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
636
637 if (attr->community)
638 community_unintern (&attr->community);
639 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
640
641 if (attr->extra)
642 {
643 if (attr->extra->ecommunity)
644 ecommunity_unintern (&attr->extra->ecommunity);
645 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
646
647 if (attr->extra->cluster)
648 cluster_unintern (attr->extra->cluster);
649 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
650
651 if (attr->extra->transit)
652 transit_unintern (attr->extra->transit);
653 }
654}
655
paul718e3742002-12-13 20:15:29 +0000656/* Free bgp attribute and aspath. */
657void
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000658bgp_attr_unintern (struct attr **pattr)
paul718e3742002-12-13 20:15:29 +0000659{
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000660 struct attr *attr = *pattr;
paul718e3742002-12-13 20:15:29 +0000661 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000662 struct attr tmp;
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000663 struct attr_extra tmp_extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000664
paul718e3742002-12-13 20:15:29 +0000665 /* Decrement attribute reference. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000666 attr->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000667
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000668 tmp = *attr;
Paul Jakmab881c702010-11-23 16:35:42 +0000669
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000670 if (attr->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 {
Jorge Boncompte [DTI2]b9f1dca2012-05-07 16:53:01 +0000672 tmp.extra = &tmp_extra;
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000673 memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000674 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000675
paul718e3742002-12-13 20:15:29 +0000676 /* If reference becomes zero then free attribute object. */
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000677 if (attr->refcnt == 0)
678 {
679 ret = hash_release (attrhash, attr);
paul718e3742002-12-13 20:15:29 +0000680 assert (ret != NULL);
Jorge Boncompte [DTI2]1a2fd702012-05-07 16:53:00 +0000681 bgp_attr_extra_free (attr);
682 XFREE (MTYPE_ATTR, attr);
683 *pattr = NULL;
paul718e3742002-12-13 20:15:29 +0000684 }
685
Paul Jakmab881c702010-11-23 16:35:42 +0000686 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000687}
688
689void
690bgp_attr_flush (struct attr *attr)
691{
692 if (attr->aspath && ! attr->aspath->refcnt)
693 aspath_free (attr->aspath);
694 if (attr->community && ! attr->community->refcnt)
695 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000696 if (attr->extra)
697 {
698 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000699
Paul Jakmafb982c22007-05-04 20:15:47 +0000700 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000701 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000702 if (attre->cluster && ! attre->cluster->refcnt)
703 cluster_free (attre->cluster);
704 if (attre->transit && ! attre->transit->refcnt)
705 transit_free (attre->transit);
706 }
paul718e3742002-12-13 20:15:29 +0000707}
708
Paul Jakmab881c702010-11-23 16:35:42 +0000709/* Implement draft-scudder-idr-optional-transitive behaviour and
710 * avoid resetting sessions for malformed attributes which are
711 * are partial/optional and hence where the error likely was not
712 * introduced by the sending neighbour.
713 */
714static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000715bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
716 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000717{
Paul Jakma835315b2012-01-18 12:28:30 +0000718 struct peer *const peer = args->peer;
719 const u_int8_t flags = args->flags;
720 /* startp and length must be special-cased, as whether or not to
721 * send the attribute data with the NOTIFY depends on the error,
722 * the caller therefore signals this with the seperate length argument
723 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000724 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000725
Paul Jakmab881c702010-11-23 16:35:42 +0000726 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000727 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000728 {
729 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000730 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000731 return BGP_ATTR_PARSE_ERROR;
732
733 }
734
Paul Jakmabd471fe2012-03-15 11:30:00 +0000735 /* Adjust the stream getp to the end of the attribute, in case we can
736 * still proceed but the caller hasn't read all the attribute.
737 */
738 stream_set_getp (BGP_INPUT (peer),
739 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
740 + args->total);
741
Paul Jakma835315b2012-01-18 12:28:30 +0000742 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100743 /* where an attribute is relatively inconsequential, e.g. it does not
744 * affect route selection, and can be safely ignored, then any such
745 * attributes which are malformed should just be ignored and the route
746 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000747 */
748 case BGP_ATTR_AS4_AGGREGATOR:
749 case BGP_ATTR_AGGREGATOR:
750 case BGP_ATTR_ATOMIC_AGGREGATE:
751 return BGP_ATTR_PARSE_PROCEED;
752
753 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100754 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000755 */
756 case BGP_ATTR_ORIGIN:
757 case BGP_ATTR_AS_PATH:
758 case BGP_ATTR_NEXT_HOP:
759 case BGP_ATTR_MULTI_EXIT_DISC:
760 case BGP_ATTR_LOCAL_PREF:
761 case BGP_ATTR_COMMUNITIES:
762 case BGP_ATTR_ORIGINATOR_ID:
763 case BGP_ATTR_CLUSTER_LIST:
764 case BGP_ATTR_MP_REACH_NLRI:
765 case BGP_ATTR_MP_UNREACH_NLRI:
766 case BGP_ATTR_EXT_COMMUNITIES:
767 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000768 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000769 return BGP_ATTR_PARSE_ERROR;
770 }
771
772 /* Partial optional attributes that are malformed should not cause
773 * the whole session to be reset. Instead treat it as a withdrawal
774 * of the routes, if possible.
775 */
Paul Jakma835315b2012-01-18 12:28:30 +0000776 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
777 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
778 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000779 return BGP_ATTR_PARSE_WITHDRAW;
780
781 /* default to reset */
782 return BGP_ATTR_PARSE_ERROR;
783}
784
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400785/* Find out what is wrong with the path attribute flag bits and log the error.
786 "Flag bits" here stand for Optional, Transitive and Partial, but not for
787 Extended Length. Checking O/T/P bits at once implies, that the attribute
788 being diagnosed is defined by RFC as either a "well-known" or an "optional,
789 non-transitive" attribute. */
790static void
Paul Jakma835315b2012-01-18 12:28:30 +0000791bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
792 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400793)
794{
795 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000796 u_char real_flags = args->flags;
797 const u_int8_t attr_code = args->type;
798
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400799 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
800 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
801 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
802 if
803 (
804 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
805 CHECK_FLAG (real_flags, attr_flag_str[i].key)
806 )
807 {
Paul Jakma835315b2012-01-18 12:28:30 +0000808 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400809 LOOKUP (attr_str, attr_code),
810 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
811 attr_flag_str[i].str);
812 seen = 1;
813 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100814 if (!seen)
815 {
816 zlog (args->peer->log, LOG_DEBUG,
817 "Strange, %s called for attr %s, but no problem found with flags"
818 " (real flags 0x%x, desired 0x%x)",
819 __func__, LOOKUP (attr_str, attr_code),
820 real_flags, desired_flags);
821 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400822}
823
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000824/* Required flags for attributes. EXTLEN will be masked off when testing,
825 * as will PARTIAL for optional+transitive attributes.
826 */
827const u_int8_t attr_flags_values [] = {
828 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
829 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
830 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
831 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
832 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
833 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
834 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
835 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
836 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
837 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
838 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
839 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
840 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
841 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
842 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
843};
844static const size_t attr_flags_values_max =
845 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
846
847static int
Paul Jakma835315b2012-01-18 12:28:30 +0000848bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000849{
850 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000851 const u_int8_t flags = args->flags;
852 const u_int8_t attr_code = args->type;
853 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000854
855 /* there may be attributes we don't know about */
856 if (attr_code > attr_flags_values_max)
857 return 0;
858 if (attr_flags_values[attr_code] == 0)
859 return 0;
860
861 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
862 * 1."
863 */
864 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
865 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
866 {
867 zlog (peer->log, LOG_ERR,
868 "%s well-known attributes must have transitive flag set (%x)",
869 LOOKUP (attr_str, attr_code), flags);
870 return 1;
871 }
872
873 /* "For well-known attributes and for optional non-transitive attributes,
874 * the Partial bit MUST be set to 0."
875 */
876 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
877 {
878 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
879 {
880 zlog (peer->log, LOG_ERR,
881 "%s well-known attribute "
882 "must NOT have the partial flag set (%x)",
883 LOOKUP (attr_str, attr_code), flags);
884 return 1;
885 }
886 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
887 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
888 {
889 zlog (peer->log, LOG_ERR,
890 "%s optional + transitive attribute "
891 "must NOT have the partial flag set (%x)",
892 LOOKUP (attr_str, attr_code), flags);
893 return 1;
894 }
895 }
896
897 /* Optional transitive attributes may go through speakers that don't
898 * reocgnise them and set the Partial bit.
899 */
900 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
901 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
902 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
903
Paul Jakma683f2b82012-03-23 14:58:45 +0000904 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000905 == attr_flags_values[attr_code])
906 return 0;
907
Paul Jakma835315b2012-01-18 12:28:30 +0000908 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000909 return 1;
910}
911
paul718e3742002-12-13 20:15:29 +0000912/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000913static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000914bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000915{
Paul Jakma835315b2012-01-18 12:28:30 +0000916 struct peer *const peer = args->peer;
917 struct attr *const attr = args->attr;
918 const bgp_size_t length = args->length;
919
paul718e3742002-12-13 20:15:29 +0000920 /* If any recognized attribute has Attribute Length that conflicts
921 with the expected length (based on the attribute type code), then
922 the Error Subcode is set to Attribute Length Error. The Data
923 field contains the erroneous attribute (type, length and
924 value). */
925 if (length != 1)
926 {
927 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
928 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000929 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000930 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000931 args->total);
paul718e3742002-12-13 20:15:29 +0000932 }
933
934 /* Fetch origin attribute. */
935 attr->origin = stream_getc (BGP_INPUT (peer));
936
937 /* If the ORIGIN attribute has an undefined value, then the Error
938 Subcode is set to Invalid Origin Attribute. The Data field
939 contains the unrecognized attribute (type, length and value). */
940 if ((attr->origin != BGP_ORIGIN_IGP)
941 && (attr->origin != BGP_ORIGIN_EGP)
942 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
943 {
944 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
945 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000946 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000947 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000948 args->total);
paul718e3742002-12-13 20:15:29 +0000949 }
950
951 /* Set oring attribute flag. */
952 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
953
954 return 0;
955}
Paul Jakmaab005292010-11-27 22:48:34 +0000956
957/* Parse AS path information. This function is wrapper of
958 aspath_parse. */
959static int
Paul Jakma835315b2012-01-18 12:28:30 +0000960bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000961{
Paul Jakma835315b2012-01-18 12:28:30 +0000962 struct attr *const attr = args->attr;
963 struct peer *const peer = args->peer;
964 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000965
Paul Jakmaab005292010-11-27 22:48:34 +0000966 /*
967 * peer with AS4 => will get 4Byte ASnums
968 * otherwise, will get 16 Bit
969 */
970 attr->aspath = aspath_parse (peer->ibuf, length,
971 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
972
973 /* In case of IBGP, length will be zero. */
974 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000975 {
Paul Jakmab881c702010-11-23 16:35:42 +0000976 zlog (peer->log, LOG_ERR,
977 "Malformed AS path from %s, length is %d",
978 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000979 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000980 }
Chris Hallcddb8112010-08-09 22:31:37 +0400981
Paul Jakmaab005292010-11-27 22:48:34 +0000982 /* Set aspath attribute flag. */
983 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000984
Paul Jakmab881c702010-11-23 16:35:42 +0000985 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000986}
987
Paul Jakmab881c702010-11-23 16:35:42 +0000988static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000989bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000990{
991 /* These checks were part of bgp_attr_aspath, but with
992 * as4 we should to check aspath things when
993 * aspath synthesizing with as4_path has already taken place.
994 * Otherwise we check ASPATH and use the synthesized thing, and that is
995 * not right.
996 * So do the checks later, i.e. here
997 */
998 struct bgp *bgp = peer->bgp;
999 struct aspath *aspath;
1000
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001001 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001002 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1003 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001004 {
1005 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001006 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1007 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1008 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001009 }
1010
paul718e3742002-12-13 20:15:29 +00001011 /* First AS check for EBGP. */
1012 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1013 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001014 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001015 && ! aspath_firstas_check (attr->aspath, peer->as))
1016 {
1017 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001018 "%s incorrect first AS (must be %u)", peer->host, peer->as);
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;
paul718e3742002-12-13 20:15:29 +00001022 }
1023 }
1024
1025 /* local-as prepend */
1026 if (peer->change_local_as &&
1027 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1028 {
1029 aspath = aspath_dup (attr->aspath);
1030 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001031 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001032 attr->aspath = aspath_intern (aspath);
1033 }
1034
Paul Jakmab881c702010-11-23 16:35:42 +00001035 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001036}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001037
Paul Jakmaab005292010-11-27 22:48:34 +00001038/* Parse AS4 path information. This function is another wrapper of
1039 aspath_parse. */
1040static int
Paul Jakma835315b2012-01-18 12:28:30 +00001041bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001042{
Paul Jakma835315b2012-01-18 12:28:30 +00001043 struct peer *const peer = args->peer;
1044 struct attr *const attr = args->attr;
1045 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001046
Paul Jakmaab005292010-11-27 22:48:34 +00001047 *as4_path = aspath_parse (peer->ibuf, length, 1);
1048
Paul Jakmab881c702010-11-23 16:35:42 +00001049 /* In case of IBGP, length will be zero. */
1050 if (!*as4_path)
1051 {
1052 zlog (peer->log, LOG_ERR,
1053 "Malformed AS4 path from %s, length is %d",
1054 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001055 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001056 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001057 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001058 }
1059
Paul Jakmaab005292010-11-27 22:48:34 +00001060 /* Set aspath attribute flag. */
1061 if (as4_path)
1062 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1063
Paul Jakmab881c702010-11-23 16:35:42 +00001064 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001065}
1066
paul718e3742002-12-13 20:15:29 +00001067/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001068static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001069bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001070{
Paul Jakma835315b2012-01-18 12:28:30 +00001071 struct peer *const peer = args->peer;
1072 struct attr *const attr = args->attr;
1073 const bgp_size_t length = args->length;
1074
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001075 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001076
paul718e3742002-12-13 20:15:29 +00001077 /* Check nexthop attribute length. */
1078 if (length != 4)
1079 {
1080 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1081 length);
1082
Paul Jakma835315b2012-01-18 12:28:30 +00001083 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001084 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001085 args->total);
paul718e3742002-12-13 20:15:29 +00001086 }
1087
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001088 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1089 attribute must result in a NOTIFICATION message (this is implemented below).
1090 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1091 logged locally (this is implemented somewhere else). The UPDATE message
1092 gets ignored in any of these cases. */
1093 nexthop_n = stream_get_ipv4 (peer->ibuf);
1094 nexthop_h = ntohl (nexthop_n);
1095 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1096 {
1097 char buf[INET_ADDRSTRLEN];
1098 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1099 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001100 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001101 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001102 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001103 }
1104
1105 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001106 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1107
Paul Jakmab881c702010-11-23 16:35:42 +00001108 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001109}
1110
1111/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001112static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001113bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001114{
Paul Jakma835315b2012-01-18 12:28:30 +00001115 struct peer *const peer = args->peer;
1116 struct attr *const attr = args->attr;
1117 const bgp_size_t length = args->length;
1118
paul718e3742002-12-13 20:15:29 +00001119 /* Length check. */
1120 if (length != 4)
1121 {
1122 zlog (peer->log, LOG_ERR,
1123 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001124
Paul Jakma835315b2012-01-18 12:28:30 +00001125 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001126 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001127 args->total);
paul718e3742002-12-13 20:15:29 +00001128 }
1129
1130 attr->med = stream_getl (peer->ibuf);
1131
1132 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1133
Paul Jakmab881c702010-11-23 16:35:42 +00001134 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001135}
1136
1137/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001138static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001139bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001140{
Paul Jakma835315b2012-01-18 12:28:30 +00001141 struct peer *const peer = args->peer;
1142 struct attr *const attr = args->attr;
1143 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001144
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001145 /* Length check. */
1146 if (length != 4)
1147 {
Paul Jakma835315b2012-01-18 12:28:30 +00001148 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1149 length);
1150 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001151 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001152 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001153 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001154
paul718e3742002-12-13 20:15:29 +00001155 /* If it is contained in an UPDATE message that is received from an
1156 external peer, then this attribute MUST be ignored by the
1157 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001158 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001159 {
paul9985f832005-02-09 15:51:56 +00001160 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001161 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001162 }
1163
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001164 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001165
1166 /* Set atomic aggregate flag. */
1167 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1168
Paul Jakmab881c702010-11-23 16:35:42 +00001169 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001170}
1171
1172/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001173static int
Paul Jakma835315b2012-01-18 12:28:30 +00001174bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001175{
Paul Jakma835315b2012-01-18 12:28:30 +00001176 struct peer *const peer = args->peer;
1177 struct attr *const attr = args->attr;
1178 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001179
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001180 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001181 if (length != 0)
1182 {
Paul Jakma835315b2012-01-18 12:28:30 +00001183 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1184 length);
1185 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001186 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001187 args->total);
paul718e3742002-12-13 20:15:29 +00001188 }
1189
1190 /* Set atomic aggregate flag. */
1191 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1192
Paul Jakmab881c702010-11-23 16:35:42 +00001193 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001194}
1195
1196/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001197static int
Paul Jakma835315b2012-01-18 12:28:30 +00001198bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001199{
Paul Jakma835315b2012-01-18 12:28:30 +00001200 struct peer *const peer = args->peer;
1201 struct attr *const attr = args->attr;
1202 const bgp_size_t length = args->length;
1203
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001204 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001205 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001206
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001207 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001208 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001209 wantedlen = 8;
1210
1211 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001212 {
Paul Jakma835315b2012-01-18 12:28:30 +00001213 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1214 wantedlen, length);
1215 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001216 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001217 args->total);
paul718e3742002-12-13 20:15:29 +00001218 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001219
1220 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1221 attre->aggregator_as = stream_getl (peer->ibuf);
1222 else
1223 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001224 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001225
1226 /* Set atomic aggregate flag. */
1227 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1228
Paul Jakmab881c702010-11-23 16:35:42 +00001229 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001230}
1231
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001232/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001233static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001234bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1235 as_t *as4_aggregator_as,
1236 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001237{
Paul Jakma835315b2012-01-18 12:28:30 +00001238 struct peer *const peer = args->peer;
1239 struct attr *const attr = args->attr;
1240 const bgp_size_t length = args->length;
1241
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001242 if (length != 8)
1243 {
Paul Jakma835315b2012-01-18 12:28:30 +00001244 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1245 length);
1246 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001247 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001248 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001249 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001250
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001251 *as4_aggregator_as = stream_getl (peer->ibuf);
1252 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1253
1254 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1255
Paul Jakmab881c702010-11-23 16:35:42 +00001256 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001257}
1258
1259/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1260 */
Paul Jakmab881c702010-11-23 16:35:42 +00001261static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001262bgp_attr_munge_as4_attrs (struct peer *const peer,
1263 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001264 struct aspath *as4_path, as_t as4_aggregator,
1265 struct in_addr *as4_aggregator_addr)
1266{
1267 int ignore_as4_path = 0;
1268 struct aspath *newpath;
1269 struct attr_extra *attre = attr->extra;
1270
Paul Jakmab881c702010-11-23 16:35:42 +00001271 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001272 {
1273 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1274 * if given.
1275 * It is worth a warning though, because the peer really
1276 * should not send them
1277 */
1278 if (BGP_DEBUG(as4, AS4))
1279 {
1280 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1281 zlog_debug ("[AS4] %s %s AS4_PATH",
1282 peer->host, "AS4 capable peer, yet it sent");
1283
1284 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1285 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1286 peer->host, "AS4 capable peer, yet it sent");
1287 }
1288
Paul Jakmab881c702010-11-23 16:35:42 +00001289 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001290 }
1291
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001292 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1293 * because that may override AS4_PATH
1294 */
1295 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1296 {
Paul Jakmab881c702010-11-23 16:35:42 +00001297 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001298 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001299 assert (attre);
1300
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001301 /* received both.
1302 * if the as_number in aggregator is not AS_TRANS,
1303 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1304 * and the Aggregator shall be taken as
1305 * info on the aggregating node, and the AS_PATH
1306 * shall be taken as the AS_PATH
1307 * otherwise
1308 * the Aggregator shall be ignored and the
1309 * AS4_AGGREGATOR shall be taken as the
1310 * Aggregating node and the AS_PATH is to be
1311 * constructed "as in all other cases"
1312 */
Paul Jakmab881c702010-11-23 16:35:42 +00001313 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001314 {
1315 /* ignore */
1316 if ( BGP_DEBUG(as4, AS4))
1317 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1318 " send AGGREGATOR != AS_TRANS and"
1319 " AS4_AGGREGATOR, so ignore"
1320 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1321 ignore_as4_path = 1;
1322 }
1323 else
1324 {
1325 /* "New_aggregator shall be taken as aggregator" */
1326 attre->aggregator_as = as4_aggregator;
1327 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1328 }
1329 }
1330 else
1331 {
1332 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1333 * That is bogus - but reading the conditions
1334 * we have to handle AS4_AGGREGATOR as if it were
1335 * AGGREGATOR in that case
1336 */
1337 if ( BGP_DEBUG(as4, AS4))
1338 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1339 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1340 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001341 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001342 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1343 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1344 }
1345 }
1346
1347 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001348 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001349 {
1350 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001351 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001352 attr->aspath = aspath_intern (newpath);
1353 }
Paul Jakmab881c702010-11-23 16:35:42 +00001354 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001355}
1356
paul718e3742002-12-13 20:15:29 +00001357/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001358static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001359bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001360{
Paul Jakma835315b2012-01-18 12:28:30 +00001361 struct peer *const peer = args->peer;
1362 struct attr *const attr = args->attr;
1363 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001364
paul718e3742002-12-13 20:15:29 +00001365 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001366 {
1367 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001368 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001369 }
Paul Jakma0c466382010-12-05 17:17:26 +00001370
1371 attr->community =
1372 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1373
1374 /* XXX: fix community_parse to use stream API and remove this */
1375 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001376
Paul Jakma0c466382010-12-05 17:17:26 +00001377 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001378 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001379 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001380 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001381
paul718e3742002-12-13 20:15:29 +00001382 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1383
Paul Jakmab881c702010-11-23 16:35:42 +00001384 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001385}
1386
1387/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001388static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001389bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001390{
Paul Jakma835315b2012-01-18 12:28:30 +00001391 struct peer *const peer = args->peer;
1392 struct attr *const attr = args->attr;
1393 const bgp_size_t length = args->length;
1394
Denis Ovsienkod595b562011-09-30 15:08:54 +04001395 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001396 if (length != 4)
1397 {
1398 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1399
Paul Jakma835315b2012-01-18 12:28:30 +00001400 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001401 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001402 args->total);
paul718e3742002-12-13 20:15:29 +00001403 }
1404
Paul Jakmafb982c22007-05-04 20:15:47 +00001405 (bgp_attr_extra_get (attr))->originator_id.s_addr
1406 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001407
1408 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1409
Paul Jakmab881c702010-11-23 16:35:42 +00001410 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001411}
1412
1413/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001414static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001415bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001416{
Paul Jakma835315b2012-01-18 12:28:30 +00001417 struct peer *const peer = args->peer;
1418 struct attr *const attr = args->attr;
1419 const bgp_size_t length = args->length;
1420
paul718e3742002-12-13 20:15:29 +00001421 /* Check length. */
1422 if (length % 4)
1423 {
1424 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1425
Paul Jakma835315b2012-01-18 12:28:30 +00001426 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1427 args->total);
paul718e3742002-12-13 20:15:29 +00001428 }
1429
Paul Jakmafb982c22007-05-04 20:15:47 +00001430 (bgp_attr_extra_get (attr))->cluster
1431 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001432
1433 /* XXX: Fix cluster_parse to use stream API and then remove this */
1434 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001435
1436 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1437
Paul Jakmab881c702010-11-23 16:35:42 +00001438 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001439}
1440
1441/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001442int
Paul Jakma835315b2012-01-18 12:28:30 +00001443bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1444 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001445{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001446 afi_t afi;
1447 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001448 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001449 size_t start;
paul718e3742002-12-13 20:15:29 +00001450 int ret;
1451 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001452 struct peer *const peer = args->peer;
1453 struct attr *const attr = args->attr;
1454 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001456
paul718e3742002-12-13 20:15:29 +00001457 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001458 s = BGP_INPUT(peer);
1459 start = stream_get_getp(s);
1460
1461 /* safe to read statically sized header? */
1462#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001463#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001464 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001465 {
1466 zlog_info ("%s: %s sent invalid length, %lu",
1467 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001468 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001469 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001470
paul718e3742002-12-13 20:15:29 +00001471 /* Load AFI, SAFI. */
1472 afi = stream_getw (s);
1473 safi = stream_getc (s);
1474
1475 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001476 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001477
Paul Jakma03292802008-06-07 20:37:10 +00001478 if (LEN_LEFT < attre->mp_nexthop_len)
1479 {
1480 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1481 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001482 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001483 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001484
paul718e3742002-12-13 20:15:29 +00001485 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001486 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001487 {
1488 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001489 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001490 /* Probably needed for RFC 2283 */
1491 if (attr->nexthop.s_addr == 0)
1492 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001493 break;
1494 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001495 stream_getl (s); /* RD high */
1496 stream_getl (s); /* RD low */
1497 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001498 break;
1499#ifdef HAVE_IPV6
1500 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001501 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001502 break;
1503 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001504 stream_get (&attre->mp_nexthop_global, s, 16);
1505 stream_get (&attre->mp_nexthop_local, s, 16);
1506 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001507 {
1508 char buf1[INET6_ADDRSTRLEN];
1509 char buf2[INET6_ADDRSTRLEN];
1510
1511 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001512 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 +00001513 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001514 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001515 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001516 buf2, INET6_ADDRSTRLEN));
1517
Paul Jakmafb982c22007-05-04 20:15:47 +00001518 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001519 }
1520 break;
1521#endif /* HAVE_IPV6 */
1522 default:
Paul Jakma03292802008-06-07 20:37:10 +00001523 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1524 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001525 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001526 }
1527
Paul Jakma03292802008-06-07 20:37:10 +00001528 if (!LEN_LEFT)
1529 {
1530 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1531 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001532 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001533 }
paul718e3742002-12-13 20:15:29 +00001534
Paul Jakma6e4ab122007-04-10 19:36:48 +00001535 {
1536 u_char val;
1537 if ((val = stream_getc (s)))
1538 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1539 peer->host, val);
1540 }
1541
1542 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001543 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001544 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001545 {
1546 zlog_info ("%s: (%s) Failed to read NLRI",
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
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001551 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001552 {
1553 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001554 if (ret < 0)
1555 {
1556 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1557 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001558 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001559 }
paul718e3742002-12-13 20:15:29 +00001560 }
1561
1562 mp_update->afi = afi;
1563 mp_update->safi = safi;
1564 mp_update->nlri = stream_pnt (s);
1565 mp_update->length = nlri_len;
1566
paul9985f832005-02-09 15:51:56 +00001567 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001568
Paul Jakmab881c702010-11-23 16:35:42 +00001569 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001570#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001571}
1572
1573/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001574int
Paul Jakma835315b2012-01-18 12:28:30 +00001575bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001576 struct bgp_nlri *mp_withdraw)
1577{
1578 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001579 afi_t afi;
1580 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001581 u_int16_t withdraw_len;
1582 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001583 struct peer *const peer = args->peer;
1584 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001585
1586 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001587
1588#define BGP_MP_UNREACH_MIN_SIZE 3
1589 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001590 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001591
paul718e3742002-12-13 20:15:29 +00001592 afi = stream_getw (s);
1593 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001594
1595 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001596
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001597 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001598 {
1599 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1600 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001601 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001602 }
1603
1604 mp_withdraw->afi = afi;
1605 mp_withdraw->safi = safi;
1606 mp_withdraw->nlri = stream_pnt (s);
1607 mp_withdraw->length = withdraw_len;
1608
paul9985f832005-02-09 15:51:56 +00001609 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001610
Paul Jakmab881c702010-11-23 16:35:42 +00001611 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001612}
1613
1614/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001615static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001616bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001617{
Paul Jakma835315b2012-01-18 12:28:30 +00001618 struct peer *const peer = args->peer;
1619 struct attr *const attr = args->attr;
1620 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001621
paul718e3742002-12-13 20:15:29 +00001622 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001623 {
1624 if (attr->extra)
1625 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001626 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001627 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001628 }
Paul Jakma0c466382010-12-05 17:17:26 +00001629
1630 (bgp_attr_extra_get (attr))->ecommunity =
1631 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1632 /* XXX: fix ecommunity_parse to use stream API */
1633 stream_forward_getp (peer->ibuf, length);
1634
1635 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001636 return bgp_attr_malformed (args,
1637 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1638 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001639
paul718e3742002-12-13 20:15:29 +00001640 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1641
Paul Jakmab881c702010-11-23 16:35:42 +00001642 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001643}
1644
1645/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001646static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001647bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001648{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001649 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001650 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001651 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001652 struct peer *const peer = args->peer;
1653 struct attr *const attr = args->attr;
1654 u_char *const startp = args->startp;
1655 const u_char type = args->type;
1656 const u_char flag = args->flags;
1657 const bgp_size_t length = args->length;
1658
paul718e3742002-12-13 20:15:29 +00001659
hassof4184462005-02-01 20:13:16 +00001660 if (BGP_DEBUG (normal, NORMAL))
1661 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1662 peer->host, type, length);
1663
paul718e3742002-12-13 20:15:29 +00001664 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001665 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001666 "Unknown attribute type %d length %d is received", type, length);
1667
1668 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001669 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001670
paul718e3742002-12-13 20:15:29 +00001671 /* If any of the mandatory well-known attributes are not recognized,
1672 then the Error Subcode is set to Unrecognized Well-known
1673 Attribute. The Data field contains the unrecognized attribute
1674 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001675 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001676 {
Paul Jakma835315b2012-01-18 12:28:30 +00001677 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001678 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001679 args->total);
paul718e3742002-12-13 20:15:29 +00001680 }
1681
1682 /* Unrecognized non-transitive optional attributes must be quietly
1683 ignored and not passed along to other BGP peers. */
1684 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001685 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001686
1687 /* If a path with recognized transitive optional attribute is
1688 accepted and passed along to other BGP peers and the Partial bit
1689 in the Attribute Flags octet is set to 1 by some previous AS, it
1690 is not set back to 0 by the current AS. */
1691 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1692
1693 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001694 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001695 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001696
Paul Jakmafb982c22007-05-04 20:15:47 +00001697 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001698
1699 if (transit->val)
1700 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1701 transit->length + total);
1702 else
1703 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1704
1705 memcpy (transit->val + transit->length, startp, total);
1706 transit->length += total;
1707
Paul Jakmab881c702010-11-23 16:35:42 +00001708 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001709}
1710
1711/* Read attribute of update packet. This function is called from
1712 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001713bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001714bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1715 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1716{
1717 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001718 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001719 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001720 bgp_size_t length;
1721 u_char *startp, *endp;
1722 u_char *attr_endp;
1723 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001724 /* we need the as4_path only until we have synthesized the as_path with it */
1725 /* same goes for as4_aggregator */
1726 struct aspath *as4_path = NULL;
1727 as_t as4_aggregator = 0;
1728 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001729
1730 /* Initialize bitmap. */
1731 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1732
1733 /* End pointer of BGP attribute. */
1734 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001735
paul718e3742002-12-13 20:15:29 +00001736 /* Get attributes to the end of attribute length. */
1737 while (BGP_INPUT_PNT (peer) < endp)
1738 {
1739 /* Check remaining length check.*/
1740 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1741 {
gdtc29fdba2004-12-09 14:46:46 +00001742 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001743 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001744 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001745 peer->host,
1746 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001747
1748 bgp_notify_send (peer,
1749 BGP_NOTIFY_UPDATE_ERR,
1750 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001751 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001752 }
1753
1754 /* Fetch attribute flag and type. */
1755 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001756 /* "The lower-order four bits of the Attribute Flags octet are
1757 unused. They MUST be zero when sent and MUST be ignored when
1758 received." */
1759 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001760 type = stream_getc (BGP_INPUT (peer));
1761
Paul Jakma370b64a2007-12-22 16:49:52 +00001762 /* Check whether Extended-Length applies and is in bounds */
1763 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1764 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1765 {
1766 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001767 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001768 peer->host,
1769 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1770
1771 bgp_notify_send (peer,
1772 BGP_NOTIFY_UPDATE_ERR,
1773 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001774 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001775 }
Paul Jakma835315b2012-01-18 12:28:30 +00001776
paul718e3742002-12-13 20:15:29 +00001777 /* Check extended attribue length bit. */
1778 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1779 length = stream_getw (BGP_INPUT (peer));
1780 else
1781 length = stream_getc (BGP_INPUT (peer));
1782
1783 /* If any attribute appears more than once in the UPDATE
1784 message, then the Error Subcode is set to Malformed Attribute
1785 List. */
1786
1787 if (CHECK_BITMAP (seen, type))
1788 {
1789 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001790 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001791 peer->host, type);
1792
1793 bgp_notify_send (peer,
1794 BGP_NOTIFY_UPDATE_ERR,
1795 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001796 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001797 }
1798
1799 /* Set type to bitmap to check duplicate attribute. `type' is
1800 unsigned char so it never overflow bitmap range. */
1801
1802 SET_BITMAP (seen, type);
1803
1804 /* Overflow check. */
1805 attr_endp = BGP_INPUT_PNT (peer) + length;
1806
1807 if (attr_endp > endp)
1808 {
1809 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001810 "%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 +00001811 bgp_notify_send (peer,
1812 BGP_NOTIFY_UPDATE_ERR,
1813 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001814 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001815 }
Paul Jakma835315b2012-01-18 12:28:30 +00001816
1817 struct bgp_attr_parser_args attr_args = {
1818 .peer = peer,
1819 .length = length,
1820 .attr = attr,
1821 .type = type,
1822 .flags = flag,
1823 .startp = startp,
1824 .total = attr_endp - startp,
1825 };
1826
1827
1828 /* If any recognized attribute has Attribute Flags that conflict
1829 with the Attribute Type Code, then the Error Subcode is set to
1830 Attribute Flags Error. The Data field contains the erroneous
1831 attribute (type, length and value). */
1832 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001833 {
1834 bgp_attr_parse_ret_t ret;
1835 ret = bgp_attr_malformed (&attr_args,
1836 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1837 attr_args.total);
1838 if (ret == BGP_ATTR_PARSE_PROCEED)
1839 continue;
1840 return ret;
1841 }
paul718e3742002-12-13 20:15:29 +00001842
1843 /* OK check attribute and store it's value. */
1844 switch (type)
1845 {
1846 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001847 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001848 break;
1849 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001850 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001851 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001852 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001853 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001854 break;
paul718e3742002-12-13 20:15:29 +00001855 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001856 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001857 break;
1858 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001859 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001860 break;
1861 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001862 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001863 break;
1864 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001865 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001866 break;
1867 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001868 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001869 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001870 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001871 ret = bgp_attr_as4_aggregator (&attr_args,
1872 &as4_aggregator,
1873 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001874 break;
paul718e3742002-12-13 20:15:29 +00001875 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001876 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001877 break;
1878 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001879 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001880 break;
1881 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001882 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001883 break;
1884 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001885 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001886 break;
1887 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001888 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001889 break;
1890 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001891 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001892 break;
1893 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001894 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001895 break;
1896 }
Paul Jakmab881c702010-11-23 16:35:42 +00001897
1898 /* If hard error occured immediately return to the caller. */
1899 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001900 {
1901 zlog (peer->log, LOG_WARNING,
1902 "%s: Attribute %s, parse error",
1903 peer->host,
1904 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001905 bgp_notify_send (peer,
1906 BGP_NOTIFY_UPDATE_ERR,
1907 BGP_NOTIFY_UPDATE_MAL_ATTR);
1908 if (as4_path)
1909 aspath_unintern (&as4_path);
1910 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001911 }
Paul Jakmab881c702010-11-23 16:35:42 +00001912 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1913 {
1914
1915 zlog (peer->log, LOG_WARNING,
1916 "%s: Attribute %s, parse error - treating as withdrawal",
1917 peer->host,
1918 LOOKUP (attr_str, type));
1919 if (as4_path)
1920 aspath_unintern (&as4_path);
1921 return ret;
1922 }
1923
paul718e3742002-12-13 20:15:29 +00001924 /* Check the fetched length. */
1925 if (BGP_INPUT_PNT (peer) != attr_endp)
1926 {
1927 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001928 "%s: BGP attribute %s, fetch error",
1929 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001930 bgp_notify_send (peer,
1931 BGP_NOTIFY_UPDATE_ERR,
1932 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001933 if (as4_path)
1934 aspath_unintern (&as4_path);
1935 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001936 }
1937 }
1938
1939 /* Check final read pointer is same as end pointer. */
1940 if (BGP_INPUT_PNT (peer) != endp)
1941 {
1942 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001943 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001944 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001945 bgp_notify_send (peer,
1946 BGP_NOTIFY_UPDATE_ERR,
1947 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001948 if (as4_path)
1949 aspath_unintern (&as4_path);
1950 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001951 }
1952
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001953 /*
1954 * At this place we can see whether we got AS4_PATH and/or
1955 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1956 * We can not do this before we've read all attributes because
1957 * the as4 handling does not say whether AS4_PATH has to be sent
1958 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1959 * in relationship to AGGREGATOR.
1960 * So, to be defensive, we are not relying on any order and read
1961 * all attributes first, including these 32bit ones, and now,
1962 * afterwards, we look what and if something is to be done for as4.
1963 */
Paul Jakma835315b2012-01-18 12:28:30 +00001964 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001965 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001966 {
1967 if (as4_path)
1968 aspath_unintern (&as4_path);
1969 return BGP_ATTR_PARSE_ERROR;
1970 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001971
1972 /* At this stage, we have done all fiddling with as4, and the
1973 * resulting info is in attr->aggregator resp. attr->aspath
1974 * so we can chuck as4_aggregator and as4_path alltogether in
1975 * order to save memory
1976 */
Paul Jakmab881c702010-11-23 16:35:42 +00001977 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001978 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001979 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001980 /* The flag that we got this is still there, but that does not
1981 * do any trouble
1982 */
1983 }
1984 /*
1985 * The "rest" of the code does nothing with as4_aggregator.
1986 * there is no memory attached specifically which is not part
1987 * of the attr.
1988 * so ignoring just means do nothing.
1989 */
1990 /*
1991 * Finally do the checks on the aspath we did not do yet
1992 * because we waited for a potentially synthesized aspath.
1993 */
Paul Jakmab881c702010-11-23 16:35:42 +00001994 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001995 {
Paul Jakma835315b2012-01-18 12:28:30 +00001996 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001997 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001998 return ret;
1999 }
2000
paul718e3742002-12-13 20:15:29 +00002001 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002002 if (attr->extra && attr->extra->transit)
2003 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002004
Paul Jakmab881c702010-11-23 16:35:42 +00002005 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002006}
2007
2008/* Well-known attribute check. */
2009int
2010bgp_attr_check (struct peer *peer, struct attr *attr)
2011{
2012 u_char type = 0;
2013
2014 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2015 type = BGP_ATTR_ORIGIN;
2016
2017 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2018 type = BGP_ATTR_AS_PATH;
2019
2020 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2021 type = BGP_ATTR_NEXT_HOP;
2022
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002023 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002024 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2025 type = BGP_ATTR_LOCAL_PREF;
2026
2027 if (type)
2028 {
2029 zlog (peer->log, LOG_WARNING,
2030 "%s Missing well-known attribute %d.",
2031 peer->host, type);
2032 bgp_notify_send_with_data (peer,
2033 BGP_NOTIFY_UPDATE_ERR,
2034 BGP_NOTIFY_UPDATE_MISS_ATTR,
2035 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002036 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002037 }
Paul Jakmab881c702010-11-23 16:35:42 +00002038 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002039}
2040
2041int stream_put_prefix (struct stream *, struct prefix *);
2042
2043/* Make attribute packet. */
2044bgp_size_t
2045bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2046 struct stream *s, struct attr *attr, struct prefix *p,
2047 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002048 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002049{
paulfe69a502005-09-10 16:55:02 +00002050 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002051 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002052 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002053 int send_as4_path = 0;
2054 int send_as4_aggregator = 0;
2055 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002056
2057 if (! bgp)
2058 bgp = bgp_get_default ();
2059
2060 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002061 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002062
2063 /* Origin attribute. */
2064 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2065 stream_putc (s, BGP_ATTR_ORIGIN);
2066 stream_putc (s, 1);
2067 stream_putc (s, attr->origin);
2068
2069 /* AS path attribute. */
2070
2071 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002072 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002073 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002074 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002075 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002076 {
2077 aspath = aspath_dup (attr->aspath);
2078
2079 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2080 {
2081 /* Strip the confed info, and then stuff our path CONFED_ID
2082 on the front */
2083 aspath = aspath_delete_confed_seq (aspath);
2084 aspath = aspath_add_seq (aspath, bgp->confed_id);
2085 }
2086 else
2087 {
2088 aspath = aspath_add_seq (aspath, peer->local_as);
2089 if (peer->change_local_as)
2090 aspath = aspath_add_seq (aspath, peer->change_local_as);
2091 }
2092 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002093 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002094 {
2095 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2096 aspath = aspath_dup (attr->aspath);
2097 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2098 }
2099 else
2100 aspath = attr->aspath;
2101
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002102 /* If peer is not AS4 capable, then:
2103 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2104 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2105 * types are in it (i.e. exclude them if they are there)
2106 * AND do this only if there is at least one asnum > 65535 in the path!
2107 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2108 * all ASnums > 65535 to BGP_AS_TRANS
2109 */
paul718e3742002-12-13 20:15:29 +00002110
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002111 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2112 stream_putc (s, BGP_ATTR_AS_PATH);
2113 aspath_sizep = stream_get_endp (s);
2114 stream_putw (s, 0);
2115 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2116
2117 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2118 * in the path
2119 */
2120 if (!use32bit && aspath_has_as4 (aspath))
2121 send_as4_path = 1; /* we'll do this later, at the correct place */
2122
paul718e3742002-12-13 20:15:29 +00002123 /* Nexthop attribute. */
2124 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2125 {
2126 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2127 stream_putc (s, BGP_ATTR_NEXT_HOP);
2128 stream_putc (s, 4);
2129 if (safi == SAFI_MPLS_VPN)
2130 {
2131 if (attr->nexthop.s_addr == 0)
2132 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2133 else
2134 stream_put_ipv4 (s, attr->nexthop.s_addr);
2135 }
2136 else
2137 stream_put_ipv4 (s, attr->nexthop.s_addr);
2138 }
2139
2140 /* MED attribute. */
2141 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2142 {
2143 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2144 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2145 stream_putc (s, 4);
2146 stream_putl (s, attr->med);
2147 }
2148
2149 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002150 if (peer->sort == BGP_PEER_IBGP ||
2151 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002152 {
2153 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2154 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2155 stream_putc (s, 4);
2156 stream_putl (s, attr->local_pref);
2157 }
2158
2159 /* Atomic aggregate. */
2160 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2161 {
2162 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2163 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2164 stream_putc (s, 0);
2165 }
2166
2167 /* Aggregator. */
2168 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2169 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002170 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002171
2172 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002173 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2174 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002175
2176 if (use32bit)
2177 {
2178 /* AS4 capable peer */
2179 stream_putc (s, 8);
2180 stream_putl (s, attr->extra->aggregator_as);
2181 }
2182 else
2183 {
2184 /* 2-byte AS peer */
2185 stream_putc (s, 6);
2186
2187 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2188 if ( attr->extra->aggregator_as > 65535 )
2189 {
2190 stream_putw (s, BGP_AS_TRANS);
2191
2192 /* we have to send AS4_AGGREGATOR, too.
2193 * we'll do that later in order to send attributes in ascending
2194 * order.
2195 */
2196 send_as4_aggregator = 1;
2197 }
2198 else
2199 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2200 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002201 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002202 }
2203
2204 /* Community attribute. */
2205 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2206 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2207 {
2208 if (attr->community->size * 4 > 255)
2209 {
2210 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2211 stream_putc (s, BGP_ATTR_COMMUNITIES);
2212 stream_putw (s, attr->community->size * 4);
2213 }
2214 else
2215 {
2216 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2217 stream_putc (s, BGP_ATTR_COMMUNITIES);
2218 stream_putc (s, attr->community->size * 4);
2219 }
2220 stream_put (s, attr->community->val, attr->community->size * 4);
2221 }
2222
2223 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002224 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002225 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002226 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002227 {
2228 /* Originator ID. */
2229 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2230 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2231 stream_putc (s, 4);
2232
2233 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002234 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002235 else
2236 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002237
2238 /* Cluster list. */
2239 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2240 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2241
Paul Jakma9eda90c2007-08-30 13:36:17 +00002242 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002243 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002244 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002245 /* If this peer configuration's parent BGP has cluster_id. */
2246 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2247 stream_put_in_addr (s, &bgp->cluster_id);
2248 else
2249 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002250 stream_put (s, attr->extra->cluster->list,
2251 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002252 }
2253 else
2254 {
2255 stream_putc (s, 4);
2256 /* If this peer configuration's parent BGP has cluster_id. */
2257 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2258 stream_put_in_addr (s, &bgp->cluster_id);
2259 else
2260 stream_put_in_addr (s, &bgp->router_id);
2261 }
2262 }
2263
2264#ifdef HAVE_IPV6
2265 /* If p is IPv6 address put it into attribute. */
2266 if (p->family == AF_INET6)
2267 {
2268 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002269 struct attr_extra *attre = attr->extra;
2270
2271 assert (attr->extra);
2272
paul718e3742002-12-13 20:15:29 +00002273 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2274 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002275 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002276 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002277 stream_putw (s, AFI_IP6); /* AFI */
2278 stream_putc (s, safi); /* SAFI */
2279
Paul Jakmafb982c22007-05-04 20:15:47 +00002280 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002281
Paul Jakmafb982c22007-05-04 20:15:47 +00002282 if (attre->mp_nexthop_len == 16)
2283 stream_put (s, &attre->mp_nexthop_global, 16);
2284 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002285 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002286 stream_put (s, &attre->mp_nexthop_global, 16);
2287 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002288 }
2289
2290 /* SNPA */
2291 stream_putc (s, 0);
2292
paul718e3742002-12-13 20:15:29 +00002293 /* Prefix write. */
2294 stream_put_prefix (s, p);
2295
2296 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002297 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002298 }
2299#endif /* HAVE_IPV6 */
2300
2301 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2302 {
2303 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002304
2305 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2306 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002307 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002308 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002309 stream_putw (s, AFI_IP); /* AFI */
2310 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2311
2312 stream_putc (s, 4);
2313 stream_put_ipv4 (s, attr->nexthop.s_addr);
2314
2315 /* SNPA */
2316 stream_putc (s, 0);
2317
paul718e3742002-12-13 20:15:29 +00002318 /* Prefix write. */
2319 stream_put_prefix (s, p);
2320
2321 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002322 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002323 }
2324
2325 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2326 {
2327 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002328
2329 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2330 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002331 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002332 stream_putc (s, 0); /* Length of this attribute. */
2333 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002334 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002335
2336 stream_putc (s, 12);
2337 stream_putl (s, 0);
2338 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002339 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002340
2341 /* SNPA */
2342 stream_putc (s, 0);
2343
paul718e3742002-12-13 20:15:29 +00002344 /* Tag, RD, Prefix write. */
2345 stream_putc (s, p->prefixlen + 88);
2346 stream_put (s, tag, 3);
2347 stream_put (s, prd->val, 8);
2348 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2349
2350 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002351 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002352 }
2353
2354 /* Extended Communities attribute. */
2355 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2356 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2357 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002358 struct attr_extra *attre = attr->extra;
2359
2360 assert (attre);
2361
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002362 if (peer->sort == BGP_PEER_IBGP
2363 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002364 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002365 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002366 {
2367 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2368 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002369 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002370 }
2371 else
2372 {
2373 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2374 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002375 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002376 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002377 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002378 }
2379 else
2380 {
paul5228ad22004-06-04 17:58:18 +00002381 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002382 int tbit;
2383 int ecom_tr_size = 0;
2384 int i;
2385
Paul Jakmafb982c22007-05-04 20:15:47 +00002386 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002387 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002388 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002389 tbit = *pnt;
2390
2391 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2392 continue;
2393
2394 ecom_tr_size++;
2395 }
2396
2397 if (ecom_tr_size)
2398 {
2399 if (ecom_tr_size * 8 > 255)
2400 {
2401 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2402 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2403 stream_putw (s, ecom_tr_size * 8);
2404 }
2405 else
2406 {
2407 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2408 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2409 stream_putc (s, ecom_tr_size * 8);
2410 }
2411
Paul Jakmafb982c22007-05-04 20:15:47 +00002412 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002413 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002414 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002415 tbit = *pnt;
2416
2417 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2418 continue;
2419
2420 stream_put (s, pnt, 8);
2421 }
2422 }
paul718e3742002-12-13 20:15:29 +00002423 }
paul718e3742002-12-13 20:15:29 +00002424 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002425
2426 if ( send_as4_path )
2427 {
2428 /* If the peer is NOT As4 capable, AND */
2429 /* there are ASnums > 65535 in path THEN
2430 * give out AS4_PATH */
2431
2432 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2433 * path segments!
2434 * Hm, I wonder... confederation things *should* only be at
2435 * the beginning of an aspath, right? Then we should use
2436 * aspath_delete_confed_seq for this, because it is already
2437 * there! (JK)
2438 * Folks, talk to me: what is reasonable here!?
2439 */
2440 aspath = aspath_delete_confed_seq (aspath);
2441
2442 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2443 stream_putc (s, BGP_ATTR_AS4_PATH);
2444 aspath_sizep = stream_get_endp (s);
2445 stream_putw (s, 0);
2446 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2447 }
2448
2449 if (aspath != attr->aspath)
2450 aspath_free (aspath);
2451
2452 if ( send_as4_aggregator )
2453 {
2454 assert (attr->extra);
2455
2456 /* send AS4_AGGREGATOR, at this place */
2457 /* this section of code moved here in order to ensure the correct
2458 * *ascending* order of attributes
2459 */
2460 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2461 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2462 stream_putc (s, 8);
2463 stream_putl (s, attr->extra->aggregator_as);
2464 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2465 }
Paul Jakma41367172007-08-06 15:24:51 +00002466
paul718e3742002-12-13 20:15:29 +00002467 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002468 if (attr->extra && attr->extra->transit)
2469 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002470
2471 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002472 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002473}
2474
2475bgp_size_t
2476bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2477 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002478 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002479{
2480 unsigned long cp;
2481 unsigned long attrlen_pnt;
2482 bgp_size_t size;
2483
paul9985f832005-02-09 15:51:56 +00002484 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002485
2486 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2487 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2488
paul9985f832005-02-09 15:51:56 +00002489 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002490 stream_putc (s, 0); /* Length of this attribute. */
2491
2492 stream_putw (s, family2afi (p->family));
2493
2494 if (safi == SAFI_MPLS_VPN)
2495 {
2496 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002497 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002498
2499 /* prefix. */
2500 stream_putc (s, p->prefixlen + 88);
2501 stream_put (s, tag, 3);
2502 stream_put (s, prd->val, 8);
2503 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2504 }
2505 else
2506 {
2507 /* SAFI */
2508 stream_putc (s, safi);
2509
2510 /* prefix */
2511 stream_put_prefix (s, p);
2512 }
2513
2514 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002515 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002516 stream_putc_at (s, attrlen_pnt, size);
2517
paul9985f832005-02-09 15:51:56 +00002518 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002519}
2520
2521/* Initialization of attribute. */
2522void
paulfe69a502005-09-10 16:55:02 +00002523bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002524{
paul718e3742002-12-13 20:15:29 +00002525 aspath_init ();
2526 attrhash_init ();
2527 community_init ();
2528 ecommunity_init ();
2529 cluster_init ();
2530 transit_init ();
2531}
2532
Chris Caputo228da422009-07-18 05:44:03 +00002533void
2534bgp_attr_finish (void)
2535{
2536 aspath_finish ();
2537 attrhash_finish ();
2538 community_finish ();
2539 ecommunity_finish ();
2540 cluster_finish ();
2541 transit_finish ();
2542}
2543
paul718e3742002-12-13 20:15:29 +00002544/* Make attribute packet. */
2545void
paula3845922003-10-18 01:30:50 +00002546bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2547 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002548{
2549 unsigned long cp;
2550 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002551 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002552 struct aspath *aspath;
2553
2554 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002555 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002556
2557 /* Place holder of length. */
2558 stream_putw (s, 0);
2559
2560 /* Origin attribute. */
2561 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2562 stream_putc (s, BGP_ATTR_ORIGIN);
2563 stream_putc (s, 1);
2564 stream_putc (s, attr->origin);
2565
2566 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002567
2568 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2569 stream_putc (s, BGP_ATTR_AS_PATH);
2570 aspath_lenp = stream_get_endp (s);
2571 stream_putw (s, 0);
2572
2573 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002574
2575 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002576 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2577 if(prefix != NULL
2578#ifdef HAVE_IPV6
2579 && prefix->family != AF_INET6
2580#endif /* HAVE_IPV6 */
2581 )
2582 {
2583 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2584 stream_putc (s, BGP_ATTR_NEXT_HOP);
2585 stream_putc (s, 4);
2586 stream_put_ipv4 (s, attr->nexthop.s_addr);
2587 }
paul718e3742002-12-13 20:15:29 +00002588
2589 /* MED attribute. */
2590 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2591 {
2592 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2593 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2594 stream_putc (s, 4);
2595 stream_putl (s, attr->med);
2596 }
2597
2598 /* Local preference. */
2599 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2600 {
2601 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2602 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2603 stream_putc (s, 4);
2604 stream_putl (s, attr->local_pref);
2605 }
2606
2607 /* Atomic aggregate. */
2608 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2609 {
2610 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2611 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2612 stream_putc (s, 0);
2613 }
2614
2615 /* Aggregator. */
2616 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2617 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002618 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002619 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2620 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002621 stream_putc (s, 8);
2622 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002623 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002624 }
2625
2626 /* Community attribute. */
2627 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2628 {
2629 if (attr->community->size * 4 > 255)
2630 {
2631 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2632 stream_putc (s, BGP_ATTR_COMMUNITIES);
2633 stream_putw (s, attr->community->size * 4);
2634 }
2635 else
2636 {
2637 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2638 stream_putc (s, BGP_ATTR_COMMUNITIES);
2639 stream_putc (s, attr->community->size * 4);
2640 }
2641 stream_put (s, attr->community->val, attr->community->size * 4);
2642 }
2643
paula3845922003-10-18 01:30:50 +00002644#ifdef HAVE_IPV6
2645 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002646 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2647 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002648 {
2649 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002650 struct attr_extra *attre = attr->extra;
2651
paula3845922003-10-18 01:30:50 +00002652 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2653 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002654 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002655
2656 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002657 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002658 stream_putw(s, AFI_IP6); /* AFI */
2659 stream_putc(s, SAFI_UNICAST); /* SAFI */
2660
2661 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002662 stream_putc(s, attre->mp_nexthop_len);
2663 stream_put(s, &attre->mp_nexthop_global, 16);
2664 if (attre->mp_nexthop_len == 32)
2665 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002666
2667 /* SNPA */
2668 stream_putc(s, 0);
2669
2670 /* Prefix */
2671 stream_put_prefix(s, prefix);
2672
2673 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002674 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002675 }
2676#endif /* HAVE_IPV6 */
2677
paul718e3742002-12-13 20:15:29 +00002678 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002679 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002680 stream_putw_at (s, cp, len);
2681}