blob: 8144cd36d3045e9e58ba949ac86447280be43c32 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -070031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_route.h"
36#include "bgpd/bgp_aspath.h"
37#include "bgpd/bgp_community.h"
38#include "bgpd/bgp_debug.h"
39#include "bgpd/bgp_packet.h"
40#include "bgpd/bgp_ecommunity.h"
41
42/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070043static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000044{
45 { BGP_ATTR_ORIGIN, "ORIGIN" },
46 { BGP_ATTR_AS_PATH, "AS_PATH" },
47 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
Denis Ovsienkof8627ff2011-10-10 16:52:20 +040054 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
paul718e3742002-12-13 20:15:29 +000055 { BGP_ATTR_DPA, "DPA" },
56 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000064};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070065static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
Denis Ovsienkoafcb7672011-10-23 22:32:44 +040066
67static const struct message attr_flag_str[] =
68{
69 { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
70 { BGP_ATTR_FLAG_TRANS, "Transitive" },
71 { BGP_ATTR_FLAG_PARTIAL, "Partial" },
72 /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
73 { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
74};
75static const size_t attr_flag_str_max =
76 sizeof (attr_flag_str) / sizeof (attr_flag_str[0]);
paul718e3742002-12-13 20:15:29 +000077
Stephen Hemminger9bddac42009-05-15 09:59:51 -070078static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000079
paul94f2b392005-06-28 12:44:16 +000080static void *
Paul Jakma923de652007-04-29 18:25:17 +000081cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000082{
Paul Jakma923de652007-04-29 18:25:17 +000083 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000084 struct cluster_list *cluster;
85
86 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
87 cluster->length = val->length;
88
89 if (cluster->length)
90 {
91 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
92 memcpy (cluster->list, val->list, val->length);
93 }
94 else
95 cluster->list = NULL;
96
97 cluster->refcnt = 0;
98
99 return cluster;
100}
101
102/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +0000103static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +0000104cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +0000105{
106 struct cluster_list tmp;
107 struct cluster_list *cluster;
108
109 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +0000110 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000111
112 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
113 cluster->refcnt++;
114 return cluster;
115}
116
117int
118cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
119{
120 int i;
121
122 for (i = 0; i < cluster->length / 4; i++)
123 if (cluster->list[i].s_addr == originator.s_addr)
124 return 1;
125 return 0;
126}
127
paul94f2b392005-06-28 12:44:16 +0000128static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000129cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000130{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700131 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000132
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700133 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000134}
135
paul94f2b392005-06-28 12:44:16 +0000136static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100137cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000138{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 const struct cluster_list * cluster1 = p1;
140 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000141
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100142 return (cluster1->length == cluster2->length &&
143 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000144}
145
paul94f2b392005-06-28 12:44:16 +0000146static void
paul718e3742002-12-13 20:15:29 +0000147cluster_free (struct cluster_list *cluster)
148{
149 if (cluster->list)
150 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
151 XFREE (MTYPE_CLUSTER, cluster);
152}
153
Chris Caputo228da422009-07-18 05:44:03 +0000154#if 0
paul94f2b392005-06-28 12:44:16 +0000155static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000156cluster_dup (struct cluster_list *cluster)
157{
158 struct cluster_list *new;
159
Stephen Hemminger393deb92008-08-18 14:13:29 -0700160 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000161 new->length = cluster->length;
162
163 if (cluster->length)
164 {
165 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
166 memcpy (new->list, cluster->list, cluster->length);
167 }
168 else
169 new->list = NULL;
170
171 return new;
172}
Chris Caputo228da422009-07-18 05:44:03 +0000173#endif
paul718e3742002-12-13 20:15:29 +0000174
paul94f2b392005-06-28 12:44:16 +0000175static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000176cluster_intern (struct cluster_list *cluster)
177{
178 struct cluster_list *find;
179
180 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
181 find->refcnt++;
182
183 return find;
184}
185
186void
187cluster_unintern (struct cluster_list *cluster)
188{
paul718e3742002-12-13 20:15:29 +0000189 if (cluster->refcnt)
190 cluster->refcnt--;
191
192 if (cluster->refcnt == 0)
193 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400194 hash_release (cluster_hash, cluster);
paul718e3742002-12-13 20:15:29 +0000195 cluster_free (cluster);
196 }
197}
198
paul94f2b392005-06-28 12:44:16 +0000199static void
200cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000201{
202 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
203}
Chris Caputo228da422009-07-18 05:44:03 +0000204
205static void
206cluster_finish (void)
207{
208 hash_free (cluster_hash);
209 cluster_hash = NULL;
210}
paul718e3742002-12-13 20:15:29 +0000211
212/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700213static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000214
paul94f2b392005-06-28 12:44:16 +0000215static void
paul718e3742002-12-13 20:15:29 +0000216transit_free (struct transit *transit)
217{
218 if (transit->val)
219 XFREE (MTYPE_TRANSIT_VAL, transit->val);
220 XFREE (MTYPE_TRANSIT, transit);
221}
222
Paul Jakma923de652007-04-29 18:25:17 +0000223
paul94f2b392005-06-28 12:44:16 +0000224static void *
Paul Jakma923de652007-04-29 18:25:17 +0000225transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000226{
227 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000228 return p;
paul718e3742002-12-13 20:15:29 +0000229}
230
paul94f2b392005-06-28 12:44:16 +0000231static struct transit *
paul718e3742002-12-13 20:15:29 +0000232transit_intern (struct transit *transit)
233{
234 struct transit *find;
235
236 find = hash_get (transit_hash, transit, transit_hash_alloc);
237 if (find != transit)
238 transit_free (transit);
239 find->refcnt++;
240
241 return find;
242}
243
244void
245transit_unintern (struct transit *transit)
246{
paul718e3742002-12-13 20:15:29 +0000247 if (transit->refcnt)
248 transit->refcnt--;
249
250 if (transit->refcnt == 0)
251 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400252 hash_release (transit_hash, transit);
paul718e3742002-12-13 20:15:29 +0000253 transit_free (transit);
254 }
255}
256
paul94f2b392005-06-28 12:44:16 +0000257static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000258transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000259{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700260 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000261
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700262 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000263}
264
paul94f2b392005-06-28 12:44:16 +0000265static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100266transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000267{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100268 const struct transit * transit1 = p1;
269 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000270
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100271 return (transit1->length == transit2->length &&
272 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000273}
274
paul94f2b392005-06-28 12:44:16 +0000275static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800276transit_init (void)
paul718e3742002-12-13 20:15:29 +0000277{
278 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
279}
Chris Caputo228da422009-07-18 05:44:03 +0000280
281static void
282transit_finish (void)
283{
284 hash_free (transit_hash);
285 transit_hash = NULL;
286}
paul718e3742002-12-13 20:15:29 +0000287
288/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700289static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000290
Paul Jakmafb982c22007-05-04 20:15:47 +0000291static struct attr_extra *
292bgp_attr_extra_new (void)
293{
294 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
295}
296
297void
298bgp_attr_extra_free (struct attr *attr)
299{
300 if (attr->extra)
301 {
302 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
303 attr->extra = NULL;
304 }
305}
306
307struct attr_extra *
308bgp_attr_extra_get (struct attr *attr)
309{
310 if (!attr->extra)
311 attr->extra = bgp_attr_extra_new();
312 return attr->extra;
313}
314
315/* Shallow copy of an attribute
316 * Though, not so shallow that it doesn't copy the contents
317 * of the attr_extra pointed to by 'extra'
318 */
319void
320bgp_attr_dup (struct attr *new, struct attr *orig)
321{
322 *new = *orig;
323 if (orig->extra)
324 {
325 new->extra = bgp_attr_extra_new();
326 *new->extra = *orig->extra;
327 }
328}
329
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000330unsigned long int
331attr_count (void)
332{
333 return attrhash->count;
334}
335
336unsigned long int
337attr_unknown_count (void)
338{
339 return transit_hash->count;
340}
341
paul718e3742002-12-13 20:15:29 +0000342unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000343attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000344{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700345 const struct attr * attr = (struct attr *) p;
346 uint32_t key = 0;
347#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000348
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700349 MIX(attr->origin);
350 MIX(attr->nexthop.s_addr);
351 MIX(attr->med);
352 MIX(attr->local_pref);
353
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000354 key += attr->origin;
355 key += attr->nexthop.s_addr;
356 key += attr->med;
357 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000358
359 if (attr->extra)
360 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700361 MIX(attr->extra->aggregator_as);
362 MIX(attr->extra->aggregator_addr.s_addr);
363 MIX(attr->extra->weight);
364 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000365 }
366
paul718e3742002-12-13 20:15:29 +0000367 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700368 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000369 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700370 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000371
372 if (attr->extra)
373 {
374 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700375 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000376 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700377 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000378 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700379 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000380
381#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700382 MIX(attr->extra->mp_nexthop_len);
Paul Jakma31d0f1b2011-03-29 14:18:49 +0100383 key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
384 key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000385#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 }
paul718e3742002-12-13 20:15:29 +0000387
388 return key;
389}
390
391int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100392attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000393{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100394 const struct attr * attr1 = p1;
395 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000396
paul718e3742002-12-13 20:15:29 +0000397 if (attr1->flag == attr2->flag
398 && attr1->origin == attr2->origin
399 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000400 && attr1->aspath == attr2->aspath
401 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000402 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000403 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000404 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100405 const struct attr_extra *ae1 = attr1->extra;
406 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000407
408 if (ae1 && ae2
409 && ae1->aggregator_as == ae2->aggregator_as
410 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
411 && ae1->weight == ae2->weight
412#ifdef HAVE_IPV6
413 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
414 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
415 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
416#endif /* HAVE_IPV6 */
417 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
418 && ae1->ecommunity == ae2->ecommunity
419 && ae1->cluster == ae2->cluster
420 && ae1->transit == ae2->transit)
421 return 1;
422 else if (ae1 || ae2)
423 return 0;
424 /* neither attribute has extra attributes, so they're same */
425 return 1;
426 }
paul718e3742002-12-13 20:15:29 +0000427 else
428 return 0;
429}
430
paul94f2b392005-06-28 12:44:16 +0000431static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100432attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000433{
434 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
435}
436
paul94f2b392005-06-28 12:44:16 +0000437static void
Chris Caputo228da422009-07-18 05:44:03 +0000438attrhash_finish (void)
439{
440 hash_free (attrhash);
441 attrhash = NULL;
442}
443
444static void
paul718e3742002-12-13 20:15:29 +0000445attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
446{
447 struct attr *attr = backet->data;
448
449 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
450 inet_ntoa (attr->nexthop), VTY_NEWLINE);
451}
452
453void
454attr_show_all (struct vty *vty)
455{
456 hash_iterate (attrhash,
457 (void (*)(struct hash_backet *, void *))
458 attr_show_all_iterator,
459 vty);
460}
461
paul94f2b392005-06-28 12:44:16 +0000462static void *
Paul Jakma923de652007-04-29 18:25:17 +0000463bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000464{
Paul Jakma923de652007-04-29 18:25:17 +0000465 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000466 struct attr *attr;
467
468 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
469 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000470 if (val->extra)
471 {
472 attr->extra = bgp_attr_extra_new ();
473 *attr->extra = *val->extra;
474 }
paul718e3742002-12-13 20:15:29 +0000475 attr->refcnt = 0;
476 return attr;
477}
478
479/* Internet argument attribute. */
480struct attr *
481bgp_attr_intern (struct attr *attr)
482{
483 struct attr *find;
484
485 /* Intern referenced strucutre. */
486 if (attr->aspath)
487 {
488 if (! attr->aspath->refcnt)
489 attr->aspath = aspath_intern (attr->aspath);
490 else
491 attr->aspath->refcnt++;
492 }
493 if (attr->community)
494 {
495 if (! attr->community->refcnt)
496 attr->community = community_intern (attr->community);
497 else
498 attr->community->refcnt++;
499 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000500 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000501 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000502 struct attr_extra *attre = attr->extra;
503
504 if (attre->ecommunity)
505 {
506 if (! attre->ecommunity->refcnt)
507 attre->ecommunity = ecommunity_intern (attre->ecommunity);
508 else
509 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000510
Paul Jakmafb982c22007-05-04 20:15:47 +0000511 }
512 if (attre->cluster)
513 {
514 if (! attre->cluster->refcnt)
515 attre->cluster = cluster_intern (attre->cluster);
516 else
517 attre->cluster->refcnt++;
518 }
519 if (attre->transit)
520 {
521 if (! attre->transit->refcnt)
522 attre->transit = transit_intern (attre->transit);
523 else
524 attre->transit->refcnt++;
525 }
paul718e3742002-12-13 20:15:29 +0000526 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000527
paul718e3742002-12-13 20:15:29 +0000528 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
529 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000530
paul718e3742002-12-13 20:15:29 +0000531 return find;
532}
533
Paul Jakma03e214c2007-04-29 18:31:07 +0000534
paul718e3742002-12-13 20:15:29 +0000535/* Make network statement's attribute. */
536struct attr *
537bgp_attr_default_set (struct attr *attr, u_char origin)
538{
539 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000540 bgp_attr_extra_get (attr);
541
paul718e3742002-12-13 20:15:29 +0000542 attr->origin = origin;
543 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
544 attr->aspath = aspath_empty ();
545 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000546 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000547 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
548#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000549 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000550#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000551
paul718e3742002-12-13 20:15:29 +0000552 return attr;
553}
554
Paul Jakma03e214c2007-04-29 18:31:07 +0000555
paul718e3742002-12-13 20:15:29 +0000556/* Make network statement's attribute. */
557struct attr *
558bgp_attr_default_intern (u_char origin)
559{
560 struct attr attr;
561 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000562
563 memset (&attr, 0, sizeof (struct attr));
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400564 bgp_attr_extra_get (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000565
Paul Jakma03e214c2007-04-29 18:31:07 +0000566 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000567
568 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000569 bgp_attr_extra_free (&attr);
570
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000571 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000572 return new;
573}
574
575struct attr *
576bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
577 struct aspath *aspath,
578 struct community *community, int as_set)
579{
580 struct attr attr;
581 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000582 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000583
584 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000585 attre = bgp_attr_extra_get (&attr);
586
paul718e3742002-12-13 20:15:29 +0000587 /* Origin attribute. */
588 attr.origin = origin;
589 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
590
591 /* AS path attribute. */
592 if (aspath)
593 attr.aspath = aspath_intern (aspath);
594 else
595 attr.aspath = aspath_empty ();
596 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
597
598 /* Next hop attribute. */
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
600
601 if (community)
602 {
603 attr.community = community;
604 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
605 }
606
Paul Jakmafb982c22007-05-04 20:15:47 +0000607 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000608#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000609 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000610#endif
611 if (! as_set)
612 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
613 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
614 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000616 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->aggregator_as = bgp->as;
618 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000619
620 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000621 bgp_attr_extra_free (&attr);
622
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000623 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000624 return new;
625}
626
Paul Jakmab881c702010-11-23 16:35:42 +0000627/* Unintern just the sub-components of the attr, but not the attr */
628void
629bgp_attr_unintern_sub (struct attr *attr)
630{
631 /* aspath refcount shoud be decrement. */
632 if (attr->aspath)
633 aspath_unintern (&attr->aspath);
634 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
635
636 if (attr->community)
637 community_unintern (&attr->community);
638 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
639
640 if (attr->extra)
641 {
642 if (attr->extra->ecommunity)
643 ecommunity_unintern (&attr->extra->ecommunity);
644 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
645
646 if (attr->extra->cluster)
647 cluster_unintern (attr->extra->cluster);
648 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
649
650 if (attr->extra->transit)
651 transit_unintern (attr->extra->transit);
652 }
653}
654
paul718e3742002-12-13 20:15:29 +0000655/* Free bgp attribute and aspath. */
656void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000657bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000658{
659 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000660 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661
paul718e3742002-12-13 20:15:29 +0000662 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000663 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000664
665 tmp = *(*attr);
666
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000667 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000668 {
Paul Jakmab881c702010-11-23 16:35:42 +0000669 tmp.extra = bgp_attr_extra_new ();
670 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672
paul718e3742002-12-13 20:15:29 +0000673 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000674 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000675 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000676 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000677 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000678 bgp_attr_extra_free (*attr);
679 XFREE (MTYPE_ATTR, *attr);
680 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000681 }
682
Paul Jakmab881c702010-11-23 16:35:42 +0000683 bgp_attr_unintern_sub (&tmp);
Oleg A. Arkhangelskyce0af6f2011-12-03 15:18:19 +0400684 bgp_attr_extra_free (&tmp);
paul718e3742002-12-13 20:15:29 +0000685}
686
687void
688bgp_attr_flush (struct attr *attr)
689{
690 if (attr->aspath && ! attr->aspath->refcnt)
691 aspath_free (attr->aspath);
692 if (attr->community && ! attr->community->refcnt)
693 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000694 if (attr->extra)
695 {
696 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000697
Paul Jakmafb982c22007-05-04 20:15:47 +0000698 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000699 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000700 if (attre->cluster && ! attre->cluster->refcnt)
701 cluster_free (attre->cluster);
702 if (attre->transit && ! attre->transit->refcnt)
703 transit_free (attre->transit);
704 }
paul718e3742002-12-13 20:15:29 +0000705}
706
Paul Jakmab881c702010-11-23 16:35:42 +0000707/* Implement draft-scudder-idr-optional-transitive behaviour and
708 * avoid resetting sessions for malformed attributes which are
709 * are partial/optional and hence where the error likely was not
710 * introduced by the sending neighbour.
711 */
712static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000713bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
714 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000715{
Paul Jakma835315b2012-01-18 12:28:30 +0000716 struct peer *const peer = args->peer;
717 const u_int8_t flags = args->flags;
718 /* startp and length must be special-cased, as whether or not to
719 * send the attribute data with the NOTIFY depends on the error,
720 * the caller therefore signals this with the seperate length argument
721 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000722 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000723
Paul Jakmab881c702010-11-23 16:35:42 +0000724 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000725 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000726 {
727 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000728 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000729 return BGP_ATTR_PARSE_ERROR;
730
731 }
732
Paul Jakmabd471fe2012-03-15 11:30:00 +0000733 /* Adjust the stream getp to the end of the attribute, in case we can
734 * still proceed but the caller hasn't read all the attribute.
735 */
736 stream_set_getp (BGP_INPUT (peer),
737 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
738 + args->total);
739
Paul Jakma835315b2012-01-18 12:28:30 +0000740 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100741 /* where an attribute is relatively inconsequential, e.g. it does not
742 * affect route selection, and can be safely ignored, then any such
743 * attributes which are malformed should just be ignored and the route
744 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000745 */
746 case BGP_ATTR_AS4_AGGREGATOR:
747 case BGP_ATTR_AGGREGATOR:
748 case BGP_ATTR_ATOMIC_AGGREGATE:
749 return BGP_ATTR_PARSE_PROCEED;
750
751 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100752 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000753 */
754 case BGP_ATTR_ORIGIN:
755 case BGP_ATTR_AS_PATH:
756 case BGP_ATTR_NEXT_HOP:
757 case BGP_ATTR_MULTI_EXIT_DISC:
758 case BGP_ATTR_LOCAL_PREF:
759 case BGP_ATTR_COMMUNITIES:
760 case BGP_ATTR_ORIGINATOR_ID:
761 case BGP_ATTR_CLUSTER_LIST:
762 case BGP_ATTR_MP_REACH_NLRI:
763 case BGP_ATTR_MP_UNREACH_NLRI:
764 case BGP_ATTR_EXT_COMMUNITIES:
765 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000766 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000767 return BGP_ATTR_PARSE_ERROR;
768 }
769
770 /* Partial optional attributes that are malformed should not cause
771 * the whole session to be reset. Instead treat it as a withdrawal
772 * of the routes, if possible.
773 */
Paul Jakma835315b2012-01-18 12:28:30 +0000774 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
775 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
776 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000777 return BGP_ATTR_PARSE_WITHDRAW;
778
779 /* default to reset */
780 return BGP_ATTR_PARSE_ERROR;
781}
782
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400783/* Find out what is wrong with the path attribute flag bits and log the error.
784 "Flag bits" here stand for Optional, Transitive and Partial, but not for
785 Extended Length. Checking O/T/P bits at once implies, that the attribute
786 being diagnosed is defined by RFC as either a "well-known" or an "optional,
787 non-transitive" attribute. */
788static void
Paul Jakma835315b2012-01-18 12:28:30 +0000789bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
790 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400791)
792{
793 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000794 u_char real_flags = args->flags;
795 const u_int8_t attr_code = args->type;
796
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400797 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
798 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
799 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
800 if
801 (
802 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
803 CHECK_FLAG (real_flags, attr_flag_str[i].key)
804 )
805 {
Paul Jakma835315b2012-01-18 12:28:30 +0000806 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400807 LOOKUP (attr_str, attr_code),
808 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
809 attr_flag_str[i].str);
810 seen = 1;
811 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100812 if (!seen)
813 {
814 zlog (args->peer->log, LOG_DEBUG,
815 "Strange, %s called for attr %s, but no problem found with flags"
816 " (real flags 0x%x, desired 0x%x)",
817 __func__, LOOKUP (attr_str, attr_code),
818 real_flags, desired_flags);
819 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400820}
821
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000822/* Required flags for attributes. EXTLEN will be masked off when testing,
823 * as will PARTIAL for optional+transitive attributes.
824 */
825const u_int8_t attr_flags_values [] = {
826 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
827 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
828 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
829 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
830 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
831 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
832 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
833 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
834 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
835 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
836 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
837 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
838 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
839 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
840 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
841};
842static const size_t attr_flags_values_max =
843 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
844
845static int
Paul Jakma835315b2012-01-18 12:28:30 +0000846bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000847{
848 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000849 const u_int8_t flags = args->flags;
850 const u_int8_t attr_code = args->type;
851 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000852
853 /* there may be attributes we don't know about */
854 if (attr_code > attr_flags_values_max)
855 return 0;
856 if (attr_flags_values[attr_code] == 0)
857 return 0;
858
859 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
860 * 1."
861 */
862 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
863 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
864 {
865 zlog (peer->log, LOG_ERR,
866 "%s well-known attributes must have transitive flag set (%x)",
867 LOOKUP (attr_str, attr_code), flags);
868 return 1;
869 }
870
871 /* "For well-known attributes and for optional non-transitive attributes,
872 * the Partial bit MUST be set to 0."
873 */
874 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
875 {
876 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
877 {
878 zlog (peer->log, LOG_ERR,
879 "%s well-known attribute "
880 "must NOT have the partial flag set (%x)",
881 LOOKUP (attr_str, attr_code), flags);
882 return 1;
883 }
884 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
885 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
886 {
887 zlog (peer->log, LOG_ERR,
888 "%s optional + transitive attribute "
889 "must NOT have the partial flag set (%x)",
890 LOOKUP (attr_str, attr_code), flags);
891 return 1;
892 }
893 }
894
895 /* Optional transitive attributes may go through speakers that don't
896 * reocgnise them and set the Partial bit.
897 */
898 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
899 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
900 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
901
Paul Jakma683f2b82012-03-23 14:58:45 +0000902 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000903 == attr_flags_values[attr_code])
904 return 0;
905
Paul Jakma835315b2012-01-18 12:28:30 +0000906 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000907 return 1;
908}
909
paul718e3742002-12-13 20:15:29 +0000910/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000911static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000912bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000913{
Paul Jakma835315b2012-01-18 12:28:30 +0000914 struct peer *const peer = args->peer;
915 struct attr *const attr = args->attr;
916 const bgp_size_t length = args->length;
917
paul718e3742002-12-13 20:15:29 +0000918 /* If any recognized attribute has Attribute Length that conflicts
919 with the expected length (based on the attribute type code), then
920 the Error Subcode is set to Attribute Length Error. The Data
921 field contains the erroneous attribute (type, length and
922 value). */
923 if (length != 1)
924 {
925 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
926 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000927 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000928 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000929 args->total);
paul718e3742002-12-13 20:15:29 +0000930 }
931
932 /* Fetch origin attribute. */
933 attr->origin = stream_getc (BGP_INPUT (peer));
934
935 /* If the ORIGIN attribute has an undefined value, then the Error
936 Subcode is set to Invalid Origin Attribute. The Data field
937 contains the unrecognized attribute (type, length and value). */
938 if ((attr->origin != BGP_ORIGIN_IGP)
939 && (attr->origin != BGP_ORIGIN_EGP)
940 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
941 {
942 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
943 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000944 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000945 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000946 args->total);
paul718e3742002-12-13 20:15:29 +0000947 }
948
949 /* Set oring attribute flag. */
950 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
951
952 return 0;
953}
Paul Jakmaab005292010-11-27 22:48:34 +0000954
955/* Parse AS path information. This function is wrapper of
956 aspath_parse. */
957static int
Paul Jakma835315b2012-01-18 12:28:30 +0000958bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000959{
Paul Jakma835315b2012-01-18 12:28:30 +0000960 struct attr *const attr = args->attr;
961 struct peer *const peer = args->peer;
962 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000963
Paul Jakmaab005292010-11-27 22:48:34 +0000964 /*
965 * peer with AS4 => will get 4Byte ASnums
966 * otherwise, will get 16 Bit
967 */
968 attr->aspath = aspath_parse (peer->ibuf, length,
969 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
970
971 /* In case of IBGP, length will be zero. */
972 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000973 {
Paul Jakmab881c702010-11-23 16:35:42 +0000974 zlog (peer->log, LOG_ERR,
975 "Malformed AS path from %s, length is %d",
976 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000977 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000978 }
Chris Hallcddb8112010-08-09 22:31:37 +0400979
Paul Jakmaab005292010-11-27 22:48:34 +0000980 /* Set aspath attribute flag. */
981 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000982
Paul Jakmab881c702010-11-23 16:35:42 +0000983 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000984}
985
Paul Jakmab881c702010-11-23 16:35:42 +0000986static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000987bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000988{
989 /* These checks were part of bgp_attr_aspath, but with
990 * as4 we should to check aspath things when
991 * aspath synthesizing with as4_path has already taken place.
992 * Otherwise we check ASPATH and use the synthesized thing, and that is
993 * not right.
994 * So do the checks later, i.e. here
995 */
996 struct bgp *bgp = peer->bgp;
997 struct aspath *aspath;
998
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300999 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001000 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1001 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001002 {
1003 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001004 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1005 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1006 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001007 }
1008
paul718e3742002-12-13 20:15:29 +00001009 /* First AS check for EBGP. */
1010 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1011 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001012 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001013 && ! aspath_firstas_check (attr->aspath, peer->as))
1014 {
1015 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001016 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001017 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1018 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1019 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001020 }
1021 }
1022
1023 /* local-as prepend */
1024 if (peer->change_local_as &&
1025 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1026 {
1027 aspath = aspath_dup (attr->aspath);
1028 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001029 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001030 attr->aspath = aspath_intern (aspath);
1031 }
1032
Paul Jakmab881c702010-11-23 16:35:42 +00001033 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001034}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001035
Paul Jakmaab005292010-11-27 22:48:34 +00001036/* Parse AS4 path information. This function is another wrapper of
1037 aspath_parse. */
1038static int
Paul Jakma835315b2012-01-18 12:28:30 +00001039bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001040{
Paul Jakma835315b2012-01-18 12:28:30 +00001041 struct peer *const peer = args->peer;
1042 struct attr *const attr = args->attr;
1043 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001044
Paul Jakmaab005292010-11-27 22:48:34 +00001045 *as4_path = aspath_parse (peer->ibuf, length, 1);
1046
Paul Jakmab881c702010-11-23 16:35:42 +00001047 /* In case of IBGP, length will be zero. */
1048 if (!*as4_path)
1049 {
1050 zlog (peer->log, LOG_ERR,
1051 "Malformed AS4 path from %s, length is %d",
1052 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001053 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001054 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001055 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001056 }
1057
Paul Jakmaab005292010-11-27 22:48:34 +00001058 /* Set aspath attribute flag. */
1059 if (as4_path)
1060 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1061
Paul Jakmab881c702010-11-23 16:35:42 +00001062 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001063}
1064
paul718e3742002-12-13 20:15:29 +00001065/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001066static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001067bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001068{
Paul Jakma835315b2012-01-18 12:28:30 +00001069 struct peer *const peer = args->peer;
1070 struct attr *const attr = args->attr;
1071 const bgp_size_t length = args->length;
1072
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001073 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001074
paul718e3742002-12-13 20:15:29 +00001075 /* Check nexthop attribute length. */
1076 if (length != 4)
1077 {
1078 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1079 length);
1080
Paul Jakma835315b2012-01-18 12:28:30 +00001081 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001082 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001083 args->total);
paul718e3742002-12-13 20:15:29 +00001084 }
1085
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001086 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1087 attribute must result in a NOTIFICATION message (this is implemented below).
1088 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1089 logged locally (this is implemented somewhere else). The UPDATE message
1090 gets ignored in any of these cases. */
1091 nexthop_n = stream_get_ipv4 (peer->ibuf);
1092 nexthop_h = ntohl (nexthop_n);
1093 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1094 {
1095 char buf[INET_ADDRSTRLEN];
1096 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1097 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001098 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001099 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001100 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001101 }
1102
1103 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001104 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1105
Paul Jakmab881c702010-11-23 16:35:42 +00001106 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001107}
1108
1109/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001110static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001111bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001112{
Paul Jakma835315b2012-01-18 12:28:30 +00001113 struct peer *const peer = args->peer;
1114 struct attr *const attr = args->attr;
1115 const bgp_size_t length = args->length;
1116
paul718e3742002-12-13 20:15:29 +00001117 /* Length check. */
1118 if (length != 4)
1119 {
1120 zlog (peer->log, LOG_ERR,
1121 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001122
Paul Jakma835315b2012-01-18 12:28:30 +00001123 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001124 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001125 args->total);
paul718e3742002-12-13 20:15:29 +00001126 }
1127
1128 attr->med = stream_getl (peer->ibuf);
1129
1130 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1131
Paul Jakmab881c702010-11-23 16:35:42 +00001132 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001133}
1134
1135/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001136static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001137bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001138{
Paul Jakma835315b2012-01-18 12:28:30 +00001139 struct peer *const peer = args->peer;
1140 struct attr *const attr = args->attr;
1141 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001142
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001143 /* Length check. */
1144 if (length != 4)
1145 {
Paul Jakma835315b2012-01-18 12:28:30 +00001146 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1147 length);
1148 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001149 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001150 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001151 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001152
paul718e3742002-12-13 20:15:29 +00001153 /* If it is contained in an UPDATE message that is received from an
1154 external peer, then this attribute MUST be ignored by the
1155 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001156 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001157 {
paul9985f832005-02-09 15:51:56 +00001158 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001159 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001160 }
1161
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001162 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001163
1164 /* Set atomic aggregate flag. */
1165 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1166
Paul Jakmab881c702010-11-23 16:35:42 +00001167 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001168}
1169
1170/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001171static int
Paul Jakma835315b2012-01-18 12:28:30 +00001172bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001173{
Paul Jakma835315b2012-01-18 12:28:30 +00001174 struct peer *const peer = args->peer;
1175 struct attr *const attr = args->attr;
1176 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001177
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001178 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001179 if (length != 0)
1180 {
Paul Jakma835315b2012-01-18 12:28:30 +00001181 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1182 length);
1183 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001184 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001185 args->total);
paul718e3742002-12-13 20:15:29 +00001186 }
1187
1188 /* Set atomic aggregate flag. */
1189 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1190
Paul Jakmab881c702010-11-23 16:35:42 +00001191 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001192}
1193
1194/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001195static int
Paul Jakma835315b2012-01-18 12:28:30 +00001196bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001197{
Paul Jakma835315b2012-01-18 12:28:30 +00001198 struct peer *const peer = args->peer;
1199 struct attr *const attr = args->attr;
1200 const bgp_size_t length = args->length;
1201
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001202 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001203 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001204
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001206 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001207 wantedlen = 8;
1208
1209 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001210 {
Paul Jakma835315b2012-01-18 12:28:30 +00001211 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1212 wantedlen, length);
1213 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001214 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001215 args->total);
paul718e3742002-12-13 20:15:29 +00001216 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001217
1218 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1219 attre->aggregator_as = stream_getl (peer->ibuf);
1220 else
1221 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001222 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001223
1224 /* Set atomic aggregate flag. */
1225 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1226
Paul Jakmab881c702010-11-23 16:35:42 +00001227 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001228}
1229
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001230/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001231static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001232bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1233 as_t *as4_aggregator_as,
1234 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001235{
Paul Jakma835315b2012-01-18 12:28:30 +00001236 struct peer *const peer = args->peer;
1237 struct attr *const attr = args->attr;
1238 const bgp_size_t length = args->length;
1239
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001240 if (length != 8)
1241 {
Paul Jakma835315b2012-01-18 12:28:30 +00001242 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1243 length);
1244 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001245 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001246 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001247 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001248
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001249 *as4_aggregator_as = stream_getl (peer->ibuf);
1250 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1251
1252 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1253
Paul Jakmab881c702010-11-23 16:35:42 +00001254 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001255}
1256
1257/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1258 */
Paul Jakmab881c702010-11-23 16:35:42 +00001259static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001260bgp_attr_munge_as4_attrs (struct peer *const peer,
1261 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001262 struct aspath *as4_path, as_t as4_aggregator,
1263 struct in_addr *as4_aggregator_addr)
1264{
1265 int ignore_as4_path = 0;
1266 struct aspath *newpath;
1267 struct attr_extra *attre = attr->extra;
1268
Paul Jakmab881c702010-11-23 16:35:42 +00001269 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001270 {
1271 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1272 * if given.
1273 * It is worth a warning though, because the peer really
1274 * should not send them
1275 */
1276 if (BGP_DEBUG(as4, AS4))
1277 {
1278 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1279 zlog_debug ("[AS4] %s %s AS4_PATH",
1280 peer->host, "AS4 capable peer, yet it sent");
1281
1282 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1283 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1284 peer->host, "AS4 capable peer, yet it sent");
1285 }
1286
Paul Jakmab881c702010-11-23 16:35:42 +00001287 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001288 }
1289
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001290 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1291 * because that may override AS4_PATH
1292 */
1293 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1294 {
Paul Jakmab881c702010-11-23 16:35:42 +00001295 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001296 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001297 assert (attre);
1298
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001299 /* received both.
1300 * if the as_number in aggregator is not AS_TRANS,
1301 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1302 * and the Aggregator shall be taken as
1303 * info on the aggregating node, and the AS_PATH
1304 * shall be taken as the AS_PATH
1305 * otherwise
1306 * the Aggregator shall be ignored and the
1307 * AS4_AGGREGATOR shall be taken as the
1308 * Aggregating node and the AS_PATH is to be
1309 * constructed "as in all other cases"
1310 */
Paul Jakmab881c702010-11-23 16:35:42 +00001311 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001312 {
1313 /* ignore */
1314 if ( BGP_DEBUG(as4, AS4))
1315 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1316 " send AGGREGATOR != AS_TRANS and"
1317 " AS4_AGGREGATOR, so ignore"
1318 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1319 ignore_as4_path = 1;
1320 }
1321 else
1322 {
1323 /* "New_aggregator shall be taken as aggregator" */
1324 attre->aggregator_as = as4_aggregator;
1325 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1326 }
1327 }
1328 else
1329 {
1330 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1331 * That is bogus - but reading the conditions
1332 * we have to handle AS4_AGGREGATOR as if it were
1333 * AGGREGATOR in that case
1334 */
1335 if ( BGP_DEBUG(as4, AS4))
1336 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1337 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1338 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001339 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001340 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1341 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1342 }
1343 }
1344
1345 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001346 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001347 {
1348 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001349 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001350 attr->aspath = aspath_intern (newpath);
1351 }
Paul Jakmab881c702010-11-23 16:35:42 +00001352 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001353}
1354
paul718e3742002-12-13 20:15:29 +00001355/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001356static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001357bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001358{
Paul Jakma835315b2012-01-18 12:28:30 +00001359 struct peer *const peer = args->peer;
1360 struct attr *const attr = args->attr;
1361 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001362
paul718e3742002-12-13 20:15:29 +00001363 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001364 {
1365 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001366 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001367 }
Paul Jakma0c466382010-12-05 17:17:26 +00001368
1369 attr->community =
1370 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1371
1372 /* XXX: fix community_parse to use stream API and remove this */
1373 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001374
Paul Jakma0c466382010-12-05 17:17:26 +00001375 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001376 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001377 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001378 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001379
paul718e3742002-12-13 20:15:29 +00001380 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1381
Paul Jakmab881c702010-11-23 16:35:42 +00001382 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001383}
1384
1385/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001386static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001387bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001388{
Paul Jakma835315b2012-01-18 12:28:30 +00001389 struct peer *const peer = args->peer;
1390 struct attr *const attr = args->attr;
1391 const bgp_size_t length = args->length;
1392
Denis Ovsienkod595b562011-09-30 15:08:54 +04001393 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001394 if (length != 4)
1395 {
1396 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1397
Paul Jakma835315b2012-01-18 12:28:30 +00001398 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001399 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001400 args->total);
paul718e3742002-12-13 20:15:29 +00001401 }
1402
Paul Jakmafb982c22007-05-04 20:15:47 +00001403 (bgp_attr_extra_get (attr))->originator_id.s_addr
1404 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001405
1406 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1407
Paul Jakmab881c702010-11-23 16:35:42 +00001408 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001409}
1410
1411/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001412static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001413bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001414{
Paul Jakma835315b2012-01-18 12:28:30 +00001415 struct peer *const peer = args->peer;
1416 struct attr *const attr = args->attr;
1417 const bgp_size_t length = args->length;
1418
paul718e3742002-12-13 20:15:29 +00001419 /* Check length. */
1420 if (length % 4)
1421 {
1422 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1423
Paul Jakma835315b2012-01-18 12:28:30 +00001424 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1425 args->total);
paul718e3742002-12-13 20:15:29 +00001426 }
1427
Paul Jakmafb982c22007-05-04 20:15:47 +00001428 (bgp_attr_extra_get (attr))->cluster
1429 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001430
1431 /* XXX: Fix cluster_parse to use stream API and then remove this */
1432 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001433
1434 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1435
Paul Jakmab881c702010-11-23 16:35:42 +00001436 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001437}
1438
1439/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001440int
Paul Jakma835315b2012-01-18 12:28:30 +00001441bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1442 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001443{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001444 afi_t afi;
1445 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001446 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001447 size_t start;
paul718e3742002-12-13 20:15:29 +00001448 int ret;
1449 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001450 struct peer *const peer = args->peer;
1451 struct attr *const attr = args->attr;
1452 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001453 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001454
paul718e3742002-12-13 20:15:29 +00001455 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001456 s = BGP_INPUT(peer);
1457 start = stream_get_getp(s);
1458
1459 /* safe to read statically sized header? */
1460#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001461#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001462 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001463 {
1464 zlog_info ("%s: %s sent invalid length, %lu",
1465 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001466 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001467 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001468
paul718e3742002-12-13 20:15:29 +00001469 /* Load AFI, SAFI. */
1470 afi = stream_getw (s);
1471 safi = stream_getc (s);
1472
1473 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001474 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001475
Paul Jakma03292802008-06-07 20:37:10 +00001476 if (LEN_LEFT < attre->mp_nexthop_len)
1477 {
1478 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1479 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001480 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001481 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001482
paul718e3742002-12-13 20:15:29 +00001483 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001484 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001485 {
1486 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001487 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001488 /* Probably needed for RFC 2283 */
1489 if (attr->nexthop.s_addr == 0)
1490 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001491 break;
1492 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001493 stream_getl (s); /* RD high */
1494 stream_getl (s); /* RD low */
1495 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001496 break;
1497#ifdef HAVE_IPV6
1498 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001499 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001500 break;
1501 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001502 stream_get (&attre->mp_nexthop_global, s, 16);
1503 stream_get (&attre->mp_nexthop_local, s, 16);
1504 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001505 {
1506 char buf1[INET6_ADDRSTRLEN];
1507 char buf2[INET6_ADDRSTRLEN];
1508
1509 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001510 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 +00001511 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001512 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001513 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001514 buf2, INET6_ADDRSTRLEN));
1515
Paul Jakmafb982c22007-05-04 20:15:47 +00001516 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001517 }
1518 break;
1519#endif /* HAVE_IPV6 */
1520 default:
Paul Jakma03292802008-06-07 20:37:10 +00001521 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1522 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001523 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001524 }
1525
Paul Jakma03292802008-06-07 20:37:10 +00001526 if (!LEN_LEFT)
1527 {
1528 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1529 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001530 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001531 }
paul718e3742002-12-13 20:15:29 +00001532
Paul Jakma6e4ab122007-04-10 19:36:48 +00001533 {
1534 u_char val;
1535 if ((val = stream_getc (s)))
1536 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1537 peer->host, val);
1538 }
1539
1540 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001541 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001542 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001543 {
1544 zlog_info ("%s: (%s) Failed to read NLRI",
1545 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001546 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001547 }
paul718e3742002-12-13 20:15:29 +00001548
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001549 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001550 {
1551 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001552 if (ret < 0)
1553 {
1554 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1555 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001556 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001557 }
paul718e3742002-12-13 20:15:29 +00001558 }
1559
1560 mp_update->afi = afi;
1561 mp_update->safi = safi;
1562 mp_update->nlri = stream_pnt (s);
1563 mp_update->length = nlri_len;
1564
paul9985f832005-02-09 15:51:56 +00001565 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001566
Paul Jakmab881c702010-11-23 16:35:42 +00001567 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001568#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001569}
1570
1571/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001572int
Paul Jakma835315b2012-01-18 12:28:30 +00001573bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001574 struct bgp_nlri *mp_withdraw)
1575{
1576 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001577 afi_t afi;
1578 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001579 u_int16_t withdraw_len;
1580 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001581 struct peer *const peer = args->peer;
1582 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001583
1584 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001585
1586#define BGP_MP_UNREACH_MIN_SIZE 3
1587 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001588 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001589
paul718e3742002-12-13 20:15:29 +00001590 afi = stream_getw (s);
1591 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001592
1593 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001594
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001595 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001596 {
1597 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1598 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001599 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001600 }
1601
1602 mp_withdraw->afi = afi;
1603 mp_withdraw->safi = safi;
1604 mp_withdraw->nlri = stream_pnt (s);
1605 mp_withdraw->length = withdraw_len;
1606
paul9985f832005-02-09 15:51:56 +00001607 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001608
Paul Jakmab881c702010-11-23 16:35:42 +00001609 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001610}
1611
1612/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001613static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001614bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001615{
Paul Jakma835315b2012-01-18 12:28:30 +00001616 struct peer *const peer = args->peer;
1617 struct attr *const attr = args->attr;
1618 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001619
paul718e3742002-12-13 20:15:29 +00001620 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001621 {
1622 if (attr->extra)
1623 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001624 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001625 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001626 }
Paul Jakma0c466382010-12-05 17:17:26 +00001627
1628 (bgp_attr_extra_get (attr))->ecommunity =
1629 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1630 /* XXX: fix ecommunity_parse to use stream API */
1631 stream_forward_getp (peer->ibuf, length);
1632
1633 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001634 return bgp_attr_malformed (args,
1635 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1636 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001637
paul718e3742002-12-13 20:15:29 +00001638 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1639
Paul Jakmab881c702010-11-23 16:35:42 +00001640 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001641}
1642
1643/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001644static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001645bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001646{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001647 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001648 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001649 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001650 struct peer *const peer = args->peer;
1651 struct attr *const attr = args->attr;
1652 u_char *const startp = args->startp;
1653 const u_char type = args->type;
1654 const u_char flag = args->flags;
1655 const bgp_size_t length = args->length;
1656
paul718e3742002-12-13 20:15:29 +00001657
hassof4184462005-02-01 20:13:16 +00001658 if (BGP_DEBUG (normal, NORMAL))
1659 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1660 peer->host, type, length);
1661
paul718e3742002-12-13 20:15:29 +00001662 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001663 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001664 "Unknown attribute type %d length %d is received", type, length);
1665
1666 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001667 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001668
paul718e3742002-12-13 20:15:29 +00001669 /* If any of the mandatory well-known attributes are not recognized,
1670 then the Error Subcode is set to Unrecognized Well-known
1671 Attribute. The Data field contains the unrecognized attribute
1672 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001673 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001674 {
Paul Jakma835315b2012-01-18 12:28:30 +00001675 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001676 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001677 args->total);
paul718e3742002-12-13 20:15:29 +00001678 }
1679
1680 /* Unrecognized non-transitive optional attributes must be quietly
1681 ignored and not passed along to other BGP peers. */
1682 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001683 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001684
1685 /* If a path with recognized transitive optional attribute is
1686 accepted and passed along to other BGP peers and the Partial bit
1687 in the Attribute Flags octet is set to 1 by some previous AS, it
1688 is not set back to 0 by the current AS. */
1689 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1690
1691 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001692 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001693 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001694
Paul Jakmafb982c22007-05-04 20:15:47 +00001695 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001696
1697 if (transit->val)
1698 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1699 transit->length + total);
1700 else
1701 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1702
1703 memcpy (transit->val + transit->length, startp, total);
1704 transit->length += total;
1705
Paul Jakmab881c702010-11-23 16:35:42 +00001706 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001707}
1708
1709/* Read attribute of update packet. This function is called from
1710 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001711bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001712bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1713 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1714{
1715 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001716 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001717 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001718 bgp_size_t length;
1719 u_char *startp, *endp;
1720 u_char *attr_endp;
1721 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001722 /* we need the as4_path only until we have synthesized the as_path with it */
1723 /* same goes for as4_aggregator */
1724 struct aspath *as4_path = NULL;
1725 as_t as4_aggregator = 0;
1726 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001727
1728 /* Initialize bitmap. */
1729 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1730
1731 /* End pointer of BGP attribute. */
1732 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001733
paul718e3742002-12-13 20:15:29 +00001734 /* Get attributes to the end of attribute length. */
1735 while (BGP_INPUT_PNT (peer) < endp)
1736 {
1737 /* Check remaining length check.*/
1738 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1739 {
gdtc29fdba2004-12-09 14:46:46 +00001740 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001741 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001742 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001743 peer->host,
1744 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001745
1746 bgp_notify_send (peer,
1747 BGP_NOTIFY_UPDATE_ERR,
1748 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001749 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001750 }
1751
1752 /* Fetch attribute flag and type. */
1753 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001754 /* "The lower-order four bits of the Attribute Flags octet are
1755 unused. They MUST be zero when sent and MUST be ignored when
1756 received." */
1757 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001758 type = stream_getc (BGP_INPUT (peer));
1759
Paul Jakma370b64a2007-12-22 16:49:52 +00001760 /* Check whether Extended-Length applies and is in bounds */
1761 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1762 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1763 {
1764 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001765 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001766 peer->host,
1767 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1768
1769 bgp_notify_send (peer,
1770 BGP_NOTIFY_UPDATE_ERR,
1771 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001772 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001773 }
Paul Jakma835315b2012-01-18 12:28:30 +00001774
paul718e3742002-12-13 20:15:29 +00001775 /* Check extended attribue length bit. */
1776 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1777 length = stream_getw (BGP_INPUT (peer));
1778 else
1779 length = stream_getc (BGP_INPUT (peer));
1780
1781 /* If any attribute appears more than once in the UPDATE
1782 message, then the Error Subcode is set to Malformed Attribute
1783 List. */
1784
1785 if (CHECK_BITMAP (seen, type))
1786 {
1787 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001788 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001789 peer->host, type);
1790
1791 bgp_notify_send (peer,
1792 BGP_NOTIFY_UPDATE_ERR,
1793 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001794 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001795 }
1796
1797 /* Set type to bitmap to check duplicate attribute. `type' is
1798 unsigned char so it never overflow bitmap range. */
1799
1800 SET_BITMAP (seen, type);
1801
1802 /* Overflow check. */
1803 attr_endp = BGP_INPUT_PNT (peer) + length;
1804
1805 if (attr_endp > endp)
1806 {
1807 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001808 "%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 +00001809 bgp_notify_send (peer,
1810 BGP_NOTIFY_UPDATE_ERR,
1811 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001812 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001813 }
Paul Jakma835315b2012-01-18 12:28:30 +00001814
1815 struct bgp_attr_parser_args attr_args = {
1816 .peer = peer,
1817 .length = length,
1818 .attr = attr,
1819 .type = type,
1820 .flags = flag,
1821 .startp = startp,
1822 .total = attr_endp - startp,
1823 };
1824
1825
1826 /* If any recognized attribute has Attribute Flags that conflict
1827 with the Attribute Type Code, then the Error Subcode is set to
1828 Attribute Flags Error. The Data field contains the erroneous
1829 attribute (type, length and value). */
1830 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001831 {
1832 bgp_attr_parse_ret_t ret;
1833 ret = bgp_attr_malformed (&attr_args,
1834 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1835 attr_args.total);
1836 if (ret == BGP_ATTR_PARSE_PROCEED)
1837 continue;
1838 return ret;
1839 }
paul718e3742002-12-13 20:15:29 +00001840
1841 /* OK check attribute and store it's value. */
1842 switch (type)
1843 {
1844 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001845 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001846 break;
1847 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001848 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001849 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001850 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001851 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001852 break;
paul718e3742002-12-13 20:15:29 +00001853 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001854 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001855 break;
1856 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001857 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001858 break;
1859 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001860 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001861 break;
1862 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001863 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001864 break;
1865 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001866 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001867 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001868 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001869 ret = bgp_attr_as4_aggregator (&attr_args,
1870 &as4_aggregator,
1871 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001872 break;
paul718e3742002-12-13 20:15:29 +00001873 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001874 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001875 break;
1876 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001877 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001878 break;
1879 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001880 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001881 break;
1882 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001883 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001884 break;
1885 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001886 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001887 break;
1888 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001889 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001890 break;
1891 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001892 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001893 break;
1894 }
Paul Jakmab881c702010-11-23 16:35:42 +00001895
1896 /* If hard error occured immediately return to the caller. */
1897 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001898 {
1899 zlog (peer->log, LOG_WARNING,
1900 "%s: Attribute %s, parse error",
1901 peer->host,
1902 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001903 bgp_notify_send (peer,
1904 BGP_NOTIFY_UPDATE_ERR,
1905 BGP_NOTIFY_UPDATE_MAL_ATTR);
1906 if (as4_path)
1907 aspath_unintern (&as4_path);
1908 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001909 }
Paul Jakmab881c702010-11-23 16:35:42 +00001910 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1911 {
1912
1913 zlog (peer->log, LOG_WARNING,
1914 "%s: Attribute %s, parse error - treating as withdrawal",
1915 peer->host,
1916 LOOKUP (attr_str, type));
1917 if (as4_path)
1918 aspath_unintern (&as4_path);
1919 return ret;
1920 }
1921
paul718e3742002-12-13 20:15:29 +00001922 /* Check the fetched length. */
1923 if (BGP_INPUT_PNT (peer) != attr_endp)
1924 {
1925 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001926 "%s: BGP attribute %s, fetch error",
1927 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001928 bgp_notify_send (peer,
1929 BGP_NOTIFY_UPDATE_ERR,
1930 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001931 if (as4_path)
1932 aspath_unintern (&as4_path);
1933 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001934 }
1935 }
1936
1937 /* Check final read pointer is same as end pointer. */
1938 if (BGP_INPUT_PNT (peer) != endp)
1939 {
1940 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001941 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001942 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001943 bgp_notify_send (peer,
1944 BGP_NOTIFY_UPDATE_ERR,
1945 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001946 if (as4_path)
1947 aspath_unintern (&as4_path);
1948 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001949 }
1950
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001951 /*
1952 * At this place we can see whether we got AS4_PATH and/or
1953 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1954 * We can not do this before we've read all attributes because
1955 * the as4 handling does not say whether AS4_PATH has to be sent
1956 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1957 * in relationship to AGGREGATOR.
1958 * So, to be defensive, we are not relying on any order and read
1959 * all attributes first, including these 32bit ones, and now,
1960 * afterwards, we look what and if something is to be done for as4.
1961 */
Paul Jakma835315b2012-01-18 12:28:30 +00001962 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001963 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001964 {
1965 if (as4_path)
1966 aspath_unintern (&as4_path);
1967 return BGP_ATTR_PARSE_ERROR;
1968 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001969
1970 /* At this stage, we have done all fiddling with as4, and the
1971 * resulting info is in attr->aggregator resp. attr->aspath
1972 * so we can chuck as4_aggregator and as4_path alltogether in
1973 * order to save memory
1974 */
Paul Jakmab881c702010-11-23 16:35:42 +00001975 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001976 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001977 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001978 /* The flag that we got this is still there, but that does not
1979 * do any trouble
1980 */
1981 }
1982 /*
1983 * The "rest" of the code does nothing with as4_aggregator.
1984 * there is no memory attached specifically which is not part
1985 * of the attr.
1986 * so ignoring just means do nothing.
1987 */
1988 /*
1989 * Finally do the checks on the aspath we did not do yet
1990 * because we waited for a potentially synthesized aspath.
1991 */
Paul Jakmab881c702010-11-23 16:35:42 +00001992 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001993 {
Paul Jakma835315b2012-01-18 12:28:30 +00001994 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001995 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001996 return ret;
1997 }
1998
paul718e3742002-12-13 20:15:29 +00001999 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002000 if (attr->extra && attr->extra->transit)
2001 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002002
Paul Jakmab881c702010-11-23 16:35:42 +00002003 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002004}
2005
2006/* Well-known attribute check. */
2007int
2008bgp_attr_check (struct peer *peer, struct attr *attr)
2009{
2010 u_char type = 0;
2011
2012 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2013 type = BGP_ATTR_ORIGIN;
2014
2015 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2016 type = BGP_ATTR_AS_PATH;
2017
2018 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2019 type = BGP_ATTR_NEXT_HOP;
2020
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002021 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002022 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2023 type = BGP_ATTR_LOCAL_PREF;
2024
2025 if (type)
2026 {
2027 zlog (peer->log, LOG_WARNING,
2028 "%s Missing well-known attribute %d.",
2029 peer->host, type);
2030 bgp_notify_send_with_data (peer,
2031 BGP_NOTIFY_UPDATE_ERR,
2032 BGP_NOTIFY_UPDATE_MISS_ATTR,
2033 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002034 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002035 }
Paul Jakmab881c702010-11-23 16:35:42 +00002036 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002037}
2038
2039int stream_put_prefix (struct stream *, struct prefix *);
2040
2041/* Make attribute packet. */
2042bgp_size_t
2043bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2044 struct stream *s, struct attr *attr, struct prefix *p,
2045 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002046 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002047{
paulfe69a502005-09-10 16:55:02 +00002048 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002049 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002050 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002051 int send_as4_path = 0;
2052 int send_as4_aggregator = 0;
2053 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002054
2055 if (! bgp)
2056 bgp = bgp_get_default ();
2057
2058 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002059 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002060
2061 /* Origin attribute. */
2062 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2063 stream_putc (s, BGP_ATTR_ORIGIN);
2064 stream_putc (s, 1);
2065 stream_putc (s, attr->origin);
2066
2067 /* AS path attribute. */
2068
2069 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002070 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002071 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002072 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002073 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002074 {
2075 aspath = aspath_dup (attr->aspath);
2076
2077 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2078 {
2079 /* Strip the confed info, and then stuff our path CONFED_ID
2080 on the front */
2081 aspath = aspath_delete_confed_seq (aspath);
2082 aspath = aspath_add_seq (aspath, bgp->confed_id);
2083 }
2084 else
2085 {
2086 aspath = aspath_add_seq (aspath, peer->local_as);
2087 if (peer->change_local_as)
2088 aspath = aspath_add_seq (aspath, peer->change_local_as);
2089 }
2090 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002091 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002092 {
2093 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2094 aspath = aspath_dup (attr->aspath);
2095 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2096 }
2097 else
2098 aspath = attr->aspath;
2099
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002100 /* If peer is not AS4 capable, then:
2101 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2102 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2103 * types are in it (i.e. exclude them if they are there)
2104 * AND do this only if there is at least one asnum > 65535 in the path!
2105 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2106 * all ASnums > 65535 to BGP_AS_TRANS
2107 */
paul718e3742002-12-13 20:15:29 +00002108
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002109 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2110 stream_putc (s, BGP_ATTR_AS_PATH);
2111 aspath_sizep = stream_get_endp (s);
2112 stream_putw (s, 0);
2113 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2114
2115 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2116 * in the path
2117 */
2118 if (!use32bit && aspath_has_as4 (aspath))
2119 send_as4_path = 1; /* we'll do this later, at the correct place */
2120
paul718e3742002-12-13 20:15:29 +00002121 /* Nexthop attribute. */
2122 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2123 {
2124 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2125 stream_putc (s, BGP_ATTR_NEXT_HOP);
2126 stream_putc (s, 4);
2127 if (safi == SAFI_MPLS_VPN)
2128 {
2129 if (attr->nexthop.s_addr == 0)
2130 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2131 else
2132 stream_put_ipv4 (s, attr->nexthop.s_addr);
2133 }
2134 else
2135 stream_put_ipv4 (s, attr->nexthop.s_addr);
2136 }
2137
2138 /* MED attribute. */
2139 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2140 {
2141 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2142 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2143 stream_putc (s, 4);
2144 stream_putl (s, attr->med);
2145 }
2146
2147 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002148 if (peer->sort == BGP_PEER_IBGP ||
2149 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002150 {
2151 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2152 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2153 stream_putc (s, 4);
2154 stream_putl (s, attr->local_pref);
2155 }
2156
2157 /* Atomic aggregate. */
2158 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2159 {
2160 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2161 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2162 stream_putc (s, 0);
2163 }
2164
2165 /* Aggregator. */
2166 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2167 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002168 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002169
2170 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002171 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2172 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002173
2174 if (use32bit)
2175 {
2176 /* AS4 capable peer */
2177 stream_putc (s, 8);
2178 stream_putl (s, attr->extra->aggregator_as);
2179 }
2180 else
2181 {
2182 /* 2-byte AS peer */
2183 stream_putc (s, 6);
2184
2185 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2186 if ( attr->extra->aggregator_as > 65535 )
2187 {
2188 stream_putw (s, BGP_AS_TRANS);
2189
2190 /* we have to send AS4_AGGREGATOR, too.
2191 * we'll do that later in order to send attributes in ascending
2192 * order.
2193 */
2194 send_as4_aggregator = 1;
2195 }
2196 else
2197 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2198 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002199 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002200 }
2201
2202 /* Community attribute. */
2203 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2204 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2205 {
2206 if (attr->community->size * 4 > 255)
2207 {
2208 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2209 stream_putc (s, BGP_ATTR_COMMUNITIES);
2210 stream_putw (s, attr->community->size * 4);
2211 }
2212 else
2213 {
2214 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2215 stream_putc (s, BGP_ATTR_COMMUNITIES);
2216 stream_putc (s, attr->community->size * 4);
2217 }
2218 stream_put (s, attr->community->val, attr->community->size * 4);
2219 }
2220
2221 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002222 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002223 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002224 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002225 {
2226 /* Originator ID. */
2227 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2228 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2229 stream_putc (s, 4);
2230
2231 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002232 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002233 else
2234 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002235
2236 /* Cluster list. */
2237 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2238 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2239
Paul Jakma9eda90c2007-08-30 13:36:17 +00002240 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002241 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002242 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002243 /* If this peer configuration's parent BGP has cluster_id. */
2244 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2245 stream_put_in_addr (s, &bgp->cluster_id);
2246 else
2247 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002248 stream_put (s, attr->extra->cluster->list,
2249 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002250 }
2251 else
2252 {
2253 stream_putc (s, 4);
2254 /* If this peer configuration's parent BGP has cluster_id. */
2255 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2256 stream_put_in_addr (s, &bgp->cluster_id);
2257 else
2258 stream_put_in_addr (s, &bgp->router_id);
2259 }
2260 }
2261
2262#ifdef HAVE_IPV6
2263 /* If p is IPv6 address put it into attribute. */
2264 if (p->family == AF_INET6)
2265 {
2266 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002267 struct attr_extra *attre = attr->extra;
2268
2269 assert (attr->extra);
2270
paul718e3742002-12-13 20:15:29 +00002271 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2272 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002273 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002275 stream_putw (s, AFI_IP6); /* AFI */
2276 stream_putc (s, safi); /* SAFI */
2277
Paul Jakmafb982c22007-05-04 20:15:47 +00002278 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002279
Paul Jakmafb982c22007-05-04 20:15:47 +00002280 if (attre->mp_nexthop_len == 16)
2281 stream_put (s, &attre->mp_nexthop_global, 16);
2282 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002283 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002284 stream_put (s, &attre->mp_nexthop_global, 16);
2285 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002286 }
2287
2288 /* SNPA */
2289 stream_putc (s, 0);
2290
paul718e3742002-12-13 20:15:29 +00002291 /* Prefix write. */
2292 stream_put_prefix (s, p);
2293
2294 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002295 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002296 }
2297#endif /* HAVE_IPV6 */
2298
2299 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2300 {
2301 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002302
2303 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2304 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002305 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002306 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002307 stream_putw (s, AFI_IP); /* AFI */
2308 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2309
2310 stream_putc (s, 4);
2311 stream_put_ipv4 (s, attr->nexthop.s_addr);
2312
2313 /* SNPA */
2314 stream_putc (s, 0);
2315
paul718e3742002-12-13 20:15:29 +00002316 /* Prefix write. */
2317 stream_put_prefix (s, p);
2318
2319 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002320 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002321 }
2322
2323 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2324 {
2325 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002326
2327 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2328 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002329 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002330 stream_putc (s, 0); /* Length of this attribute. */
2331 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002332 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002333
2334 stream_putc (s, 12);
2335 stream_putl (s, 0);
2336 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002337 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002338
2339 /* SNPA */
2340 stream_putc (s, 0);
2341
paul718e3742002-12-13 20:15:29 +00002342 /* Tag, RD, Prefix write. */
2343 stream_putc (s, p->prefixlen + 88);
2344 stream_put (s, tag, 3);
2345 stream_put (s, prd->val, 8);
2346 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2347
2348 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002349 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002350 }
2351
2352 /* Extended Communities attribute. */
2353 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2354 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2355 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002356 struct attr_extra *attre = attr->extra;
2357
2358 assert (attre);
2359
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002360 if (peer->sort == BGP_PEER_IBGP
2361 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002362 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002363 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002364 {
2365 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2366 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002367 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002368 }
2369 else
2370 {
2371 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2372 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002373 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002374 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002375 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002376 }
2377 else
2378 {
paul5228ad22004-06-04 17:58:18 +00002379 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002380 int tbit;
2381 int ecom_tr_size = 0;
2382 int i;
2383
Paul Jakmafb982c22007-05-04 20:15:47 +00002384 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002385 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002386 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002387 tbit = *pnt;
2388
2389 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2390 continue;
2391
2392 ecom_tr_size++;
2393 }
2394
2395 if (ecom_tr_size)
2396 {
2397 if (ecom_tr_size * 8 > 255)
2398 {
2399 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2400 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2401 stream_putw (s, ecom_tr_size * 8);
2402 }
2403 else
2404 {
2405 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2406 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2407 stream_putc (s, ecom_tr_size * 8);
2408 }
2409
Paul Jakmafb982c22007-05-04 20:15:47 +00002410 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002411 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002412 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002413 tbit = *pnt;
2414
2415 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2416 continue;
2417
2418 stream_put (s, pnt, 8);
2419 }
2420 }
paul718e3742002-12-13 20:15:29 +00002421 }
paul718e3742002-12-13 20:15:29 +00002422 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002423
2424 if ( send_as4_path )
2425 {
2426 /* If the peer is NOT As4 capable, AND */
2427 /* there are ASnums > 65535 in path THEN
2428 * give out AS4_PATH */
2429
2430 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2431 * path segments!
2432 * Hm, I wonder... confederation things *should* only be at
2433 * the beginning of an aspath, right? Then we should use
2434 * aspath_delete_confed_seq for this, because it is already
2435 * there! (JK)
2436 * Folks, talk to me: what is reasonable here!?
2437 */
2438 aspath = aspath_delete_confed_seq (aspath);
2439
2440 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2441 stream_putc (s, BGP_ATTR_AS4_PATH);
2442 aspath_sizep = stream_get_endp (s);
2443 stream_putw (s, 0);
2444 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2445 }
2446
2447 if (aspath != attr->aspath)
2448 aspath_free (aspath);
2449
2450 if ( send_as4_aggregator )
2451 {
2452 assert (attr->extra);
2453
2454 /* send AS4_AGGREGATOR, at this place */
2455 /* this section of code moved here in order to ensure the correct
2456 * *ascending* order of attributes
2457 */
2458 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2459 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2460 stream_putc (s, 8);
2461 stream_putl (s, attr->extra->aggregator_as);
2462 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2463 }
Paul Jakma41367172007-08-06 15:24:51 +00002464
paul718e3742002-12-13 20:15:29 +00002465 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002466 if (attr->extra && attr->extra->transit)
2467 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002468
2469 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002470 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002471}
2472
2473bgp_size_t
2474bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2475 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002476 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002477{
2478 unsigned long cp;
2479 unsigned long attrlen_pnt;
2480 bgp_size_t size;
2481
paul9985f832005-02-09 15:51:56 +00002482 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002483
2484 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2485 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2486
paul9985f832005-02-09 15:51:56 +00002487 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002488 stream_putc (s, 0); /* Length of this attribute. */
2489
2490 stream_putw (s, family2afi (p->family));
2491
2492 if (safi == SAFI_MPLS_VPN)
2493 {
2494 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002495 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002496
2497 /* prefix. */
2498 stream_putc (s, p->prefixlen + 88);
2499 stream_put (s, tag, 3);
2500 stream_put (s, prd->val, 8);
2501 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2502 }
2503 else
2504 {
2505 /* SAFI */
2506 stream_putc (s, safi);
2507
2508 /* prefix */
2509 stream_put_prefix (s, p);
2510 }
2511
2512 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002513 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002514 stream_putc_at (s, attrlen_pnt, size);
2515
paul9985f832005-02-09 15:51:56 +00002516 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002517}
2518
2519/* Initialization of attribute. */
2520void
paulfe69a502005-09-10 16:55:02 +00002521bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002522{
paul718e3742002-12-13 20:15:29 +00002523 aspath_init ();
2524 attrhash_init ();
2525 community_init ();
2526 ecommunity_init ();
2527 cluster_init ();
2528 transit_init ();
2529}
2530
Chris Caputo228da422009-07-18 05:44:03 +00002531void
2532bgp_attr_finish (void)
2533{
2534 aspath_finish ();
2535 attrhash_finish ();
2536 community_finish ();
2537 ecommunity_finish ();
2538 cluster_finish ();
2539 transit_finish ();
2540}
2541
paul718e3742002-12-13 20:15:29 +00002542/* Make attribute packet. */
2543void
paula3845922003-10-18 01:30:50 +00002544bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2545 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002546{
2547 unsigned long cp;
2548 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002549 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002550 struct aspath *aspath;
2551
2552 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002553 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002554
2555 /* Place holder of length. */
2556 stream_putw (s, 0);
2557
2558 /* Origin attribute. */
2559 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2560 stream_putc (s, BGP_ATTR_ORIGIN);
2561 stream_putc (s, 1);
2562 stream_putc (s, attr->origin);
2563
2564 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002565
2566 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2567 stream_putc (s, BGP_ATTR_AS_PATH);
2568 aspath_lenp = stream_get_endp (s);
2569 stream_putw (s, 0);
2570
2571 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002572
2573 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002574 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2575 if(prefix != NULL
2576#ifdef HAVE_IPV6
2577 && prefix->family != AF_INET6
2578#endif /* HAVE_IPV6 */
2579 )
2580 {
2581 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2582 stream_putc (s, BGP_ATTR_NEXT_HOP);
2583 stream_putc (s, 4);
2584 stream_put_ipv4 (s, attr->nexthop.s_addr);
2585 }
paul718e3742002-12-13 20:15:29 +00002586
2587 /* MED attribute. */
2588 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2589 {
2590 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2591 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2592 stream_putc (s, 4);
2593 stream_putl (s, attr->med);
2594 }
2595
2596 /* Local preference. */
2597 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2598 {
2599 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2600 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2601 stream_putc (s, 4);
2602 stream_putl (s, attr->local_pref);
2603 }
2604
2605 /* Atomic aggregate. */
2606 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2607 {
2608 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2609 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2610 stream_putc (s, 0);
2611 }
2612
2613 /* Aggregator. */
2614 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2615 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002616 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002617 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2618 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002619 stream_putc (s, 8);
2620 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002621 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002622 }
2623
2624 /* Community attribute. */
2625 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2626 {
2627 if (attr->community->size * 4 > 255)
2628 {
2629 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2630 stream_putc (s, BGP_ATTR_COMMUNITIES);
2631 stream_putw (s, attr->community->size * 4);
2632 }
2633 else
2634 {
2635 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2636 stream_putc (s, BGP_ATTR_COMMUNITIES);
2637 stream_putc (s, attr->community->size * 4);
2638 }
2639 stream_put (s, attr->community->val, attr->community->size * 4);
2640 }
2641
paula3845922003-10-18 01:30:50 +00002642#ifdef HAVE_IPV6
2643 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002644 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2645 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002646 {
2647 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002648 struct attr_extra *attre = attr->extra;
2649
paula3845922003-10-18 01:30:50 +00002650 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2651 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002652 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002653
2654 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002655 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002656 stream_putw(s, AFI_IP6); /* AFI */
2657 stream_putc(s, SAFI_UNICAST); /* SAFI */
2658
2659 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002660 stream_putc(s, attre->mp_nexthop_len);
2661 stream_put(s, &attre->mp_nexthop_global, 16);
2662 if (attre->mp_nexthop_len == 32)
2663 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002664
2665 /* SNPA */
2666 stream_putc(s, 0);
2667
2668 /* Prefix */
2669 stream_put_prefix(s, prefix);
2670
2671 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002672 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002673 }
2674#endif /* HAVE_IPV6 */
2675
paul718e3742002-12-13 20:15:29 +00002676 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002677 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002678 stream_putw_at (s, cp, len);
2679}