blob: c21655c0725afaf6380b7d3bb26241d7efd2e0e6 [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 */
725 if (peer_sort (peer) != BGP_PEER_EBGP)
726 {
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 }
812 assert (seen);
813}
814
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000815/* Required flags for attributes. EXTLEN will be masked off when testing,
816 * as will PARTIAL for optional+transitive attributes.
817 */
818const u_int8_t attr_flags_values [] = {
819 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
820 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
821 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
822 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
823 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
824 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
825 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
826 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
827 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
828 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
829 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
830 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
831 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
832 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
833 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
834};
835static const size_t attr_flags_values_max =
836 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
837
838static int
Paul Jakma835315b2012-01-18 12:28:30 +0000839bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000840{
841 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000842 const u_int8_t flags = args->flags;
843 const u_int8_t attr_code = args->type;
844 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000845
846 /* there may be attributes we don't know about */
847 if (attr_code > attr_flags_values_max)
848 return 0;
849 if (attr_flags_values[attr_code] == 0)
850 return 0;
851
852 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
853 * 1."
854 */
855 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
856 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
857 {
858 zlog (peer->log, LOG_ERR,
859 "%s well-known attributes must have transitive flag set (%x)",
860 LOOKUP (attr_str, attr_code), flags);
861 return 1;
862 }
863
864 /* "For well-known attributes and for optional non-transitive attributes,
865 * the Partial bit MUST be set to 0."
866 */
867 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
868 {
869 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
870 {
871 zlog (peer->log, LOG_ERR,
872 "%s well-known attribute "
873 "must NOT have the partial flag set (%x)",
874 LOOKUP (attr_str, attr_code), flags);
875 return 1;
876 }
877 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
878 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
879 {
880 zlog (peer->log, LOG_ERR,
881 "%s optional + transitive attribute "
882 "must NOT have the partial flag set (%x)",
883 LOOKUP (attr_str, attr_code), flags);
884 return 1;
885 }
886 }
887
888 /* Optional transitive attributes may go through speakers that don't
889 * reocgnise them and set the Partial bit.
890 */
891 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
892 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
893 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
894
Paul Jakma683f2b82012-03-23 14:58:45 +0000895 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000896 == attr_flags_values[attr_code])
897 return 0;
898
Paul Jakma835315b2012-01-18 12:28:30 +0000899 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000900 return 1;
901}
902
paul718e3742002-12-13 20:15:29 +0000903/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000904static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000905bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000906{
Paul Jakma835315b2012-01-18 12:28:30 +0000907 struct peer *const peer = args->peer;
908 struct attr *const attr = args->attr;
909 const bgp_size_t length = args->length;
910
paul718e3742002-12-13 20:15:29 +0000911 /* If any recognized attribute has Attribute Length that conflicts
912 with the expected length (based on the attribute type code), then
913 the Error Subcode is set to Attribute Length Error. The Data
914 field contains the erroneous attribute (type, length and
915 value). */
916 if (length != 1)
917 {
918 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
919 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000920 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000921 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000922 args->total);
paul718e3742002-12-13 20:15:29 +0000923 }
924
925 /* Fetch origin attribute. */
926 attr->origin = stream_getc (BGP_INPUT (peer));
927
928 /* If the ORIGIN attribute has an undefined value, then the Error
929 Subcode is set to Invalid Origin Attribute. The Data field
930 contains the unrecognized attribute (type, length and value). */
931 if ((attr->origin != BGP_ORIGIN_IGP)
932 && (attr->origin != BGP_ORIGIN_EGP)
933 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
934 {
935 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
936 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000937 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000938 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000939 args->total);
paul718e3742002-12-13 20:15:29 +0000940 }
941
942 /* Set oring attribute flag. */
943 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
944
945 return 0;
946}
Paul Jakmaab005292010-11-27 22:48:34 +0000947
948/* Parse AS path information. This function is wrapper of
949 aspath_parse. */
950static int
Paul Jakma835315b2012-01-18 12:28:30 +0000951bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000952{
Paul Jakma835315b2012-01-18 12:28:30 +0000953 struct attr *const attr = args->attr;
954 struct peer *const peer = args->peer;
955 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000956
Paul Jakmaab005292010-11-27 22:48:34 +0000957 /*
958 * peer with AS4 => will get 4Byte ASnums
959 * otherwise, will get 16 Bit
960 */
961 attr->aspath = aspath_parse (peer->ibuf, length,
962 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
963
964 /* In case of IBGP, length will be zero. */
965 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000966 {
Paul Jakmab881c702010-11-23 16:35:42 +0000967 zlog (peer->log, LOG_ERR,
968 "Malformed AS path from %s, length is %d",
969 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000970 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000971 }
Chris Hallcddb8112010-08-09 22:31:37 +0400972
Paul Jakmaab005292010-11-27 22:48:34 +0000973 /* Set aspath attribute flag. */
974 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000975
Paul Jakmab881c702010-11-23 16:35:42 +0000976 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000977}
978
Paul Jakmab881c702010-11-23 16:35:42 +0000979static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000980bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000981{
982 /* These checks were part of bgp_attr_aspath, but with
983 * as4 we should to check aspath things when
984 * aspath synthesizing with as4_path has already taken place.
985 * Otherwise we check ASPATH and use the synthesized thing, and that is
986 * not right.
987 * So do the checks later, i.e. here
988 */
989 struct bgp *bgp = peer->bgp;
990 struct aspath *aspath;
991
paul718e3742002-12-13 20:15:29 +0000992 bgp = peer->bgp;
993
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300994 /* Confederation sanity check. */
995 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
996 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
997 {
998 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +0000999 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1000 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1001 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001002 }
1003
paul718e3742002-12-13 20:15:29 +00001004 /* First AS check for EBGP. */
1005 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1006 {
1007 if (peer_sort (peer) == BGP_PEER_EBGP
1008 && ! aspath_firstas_check (attr->aspath, peer->as))
1009 {
1010 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001011 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001012 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1013 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1014 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001015 }
1016 }
1017
1018 /* local-as prepend */
1019 if (peer->change_local_as &&
1020 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1021 {
1022 aspath = aspath_dup (attr->aspath);
1023 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001024 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001025 attr->aspath = aspath_intern (aspath);
1026 }
1027
Paul Jakmab881c702010-11-23 16:35:42 +00001028 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001029}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001030
Paul Jakmaab005292010-11-27 22:48:34 +00001031/* Parse AS4 path information. This function is another wrapper of
1032 aspath_parse. */
1033static int
Paul Jakma835315b2012-01-18 12:28:30 +00001034bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001035{
Paul Jakma835315b2012-01-18 12:28:30 +00001036 struct peer *const peer = args->peer;
1037 struct attr *const attr = args->attr;
1038 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001039
Paul Jakmaab005292010-11-27 22:48:34 +00001040 *as4_path = aspath_parse (peer->ibuf, length, 1);
1041
Paul Jakmab881c702010-11-23 16:35:42 +00001042 /* In case of IBGP, length will be zero. */
1043 if (!*as4_path)
1044 {
1045 zlog (peer->log, LOG_ERR,
1046 "Malformed AS4 path from %s, length is %d",
1047 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001048 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001049 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001050 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001051 }
1052
Paul Jakmaab005292010-11-27 22:48:34 +00001053 /* Set aspath attribute flag. */
1054 if (as4_path)
1055 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1056
Paul Jakmab881c702010-11-23 16:35:42 +00001057 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001058}
1059
paul718e3742002-12-13 20:15:29 +00001060/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001061static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001062bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001063{
Paul Jakma835315b2012-01-18 12:28:30 +00001064 struct peer *const peer = args->peer;
1065 struct attr *const attr = args->attr;
1066 const bgp_size_t length = args->length;
1067
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001068 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001069
paul718e3742002-12-13 20:15:29 +00001070 /* Check nexthop attribute length. */
1071 if (length != 4)
1072 {
1073 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1074 length);
1075
Paul Jakma835315b2012-01-18 12:28:30 +00001076 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001077 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001078 args->total);
paul718e3742002-12-13 20:15:29 +00001079 }
1080
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001081 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1082 attribute must result in a NOTIFICATION message (this is implemented below).
1083 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1084 logged locally (this is implemented somewhere else). The UPDATE message
1085 gets ignored in any of these cases. */
1086 nexthop_n = stream_get_ipv4 (peer->ibuf);
1087 nexthop_h = ntohl (nexthop_n);
1088 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1089 {
1090 char buf[INET_ADDRSTRLEN];
1091 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1092 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001093 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001094 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001095 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001096 }
1097
1098 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001099 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1100
Paul Jakmab881c702010-11-23 16:35:42 +00001101 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001102}
1103
1104/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001105static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001106bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001107{
Paul Jakma835315b2012-01-18 12:28:30 +00001108 struct peer *const peer = args->peer;
1109 struct attr *const attr = args->attr;
1110 const bgp_size_t length = args->length;
1111
paul718e3742002-12-13 20:15:29 +00001112 /* Length check. */
1113 if (length != 4)
1114 {
1115 zlog (peer->log, LOG_ERR,
1116 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001117
Paul Jakma835315b2012-01-18 12:28:30 +00001118 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001119 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001120 args->total);
paul718e3742002-12-13 20:15:29 +00001121 }
1122
1123 attr->med = stream_getl (peer->ibuf);
1124
1125 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1126
Paul Jakmab881c702010-11-23 16:35:42 +00001127 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001128}
1129
1130/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001131static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001132bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001133{
Paul Jakma835315b2012-01-18 12:28:30 +00001134 struct peer *const peer = args->peer;
1135 struct attr *const attr = args->attr;
1136 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001137
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001138 /* Length check. */
1139 if (length != 4)
1140 {
Paul Jakma835315b2012-01-18 12:28:30 +00001141 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1142 length);
1143 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001144 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001145 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001146 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001147
paul718e3742002-12-13 20:15:29 +00001148 /* If it is contained in an UPDATE message that is received from an
1149 external peer, then this attribute MUST be ignored by the
1150 receiving speaker. */
1151 if (peer_sort (peer) == BGP_PEER_EBGP)
1152 {
paul9985f832005-02-09 15:51:56 +00001153 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001154 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001155 }
1156
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001157 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001158
1159 /* Set atomic aggregate flag. */
1160 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1161
Paul Jakmab881c702010-11-23 16:35:42 +00001162 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001163}
1164
1165/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001166static int
Paul Jakma835315b2012-01-18 12:28:30 +00001167bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001168{
Paul Jakma835315b2012-01-18 12:28:30 +00001169 struct peer *const peer = args->peer;
1170 struct attr *const attr = args->attr;
1171 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001172
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001173 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001174 if (length != 0)
1175 {
Paul Jakma835315b2012-01-18 12:28:30 +00001176 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1177 length);
1178 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001179 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001180 args->total);
paul718e3742002-12-13 20:15:29 +00001181 }
1182
1183 /* Set atomic aggregate flag. */
1184 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1185
Paul Jakmab881c702010-11-23 16:35:42 +00001186 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001187}
1188
1189/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001190static int
Paul Jakma835315b2012-01-18 12:28:30 +00001191bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001192{
Paul Jakma835315b2012-01-18 12:28:30 +00001193 struct peer *const peer = args->peer;
1194 struct attr *const attr = args->attr;
1195 const bgp_size_t length = args->length;
1196
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001197 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001198 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001199
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001200 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001201 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001202 wantedlen = 8;
1203
1204 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001205 {
Paul Jakma835315b2012-01-18 12:28:30 +00001206 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1207 wantedlen, length);
1208 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001209 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001210 args->total);
paul718e3742002-12-13 20:15:29 +00001211 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001212
1213 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1214 attre->aggregator_as = stream_getl (peer->ibuf);
1215 else
1216 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001217 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001218
1219 /* Set atomic aggregate flag. */
1220 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1221
Paul Jakmab881c702010-11-23 16:35:42 +00001222 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001223}
1224
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001225/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001226static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001227bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1228 as_t *as4_aggregator_as,
1229 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001230{
Paul Jakma835315b2012-01-18 12:28:30 +00001231 struct peer *const peer = args->peer;
1232 struct attr *const attr = args->attr;
1233 const bgp_size_t length = args->length;
1234
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001235 if (length != 8)
1236 {
Paul Jakma835315b2012-01-18 12:28:30 +00001237 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1238 length);
1239 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001240 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001241 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001242 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001243
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001244 *as4_aggregator_as = stream_getl (peer->ibuf);
1245 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1246
1247 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1248
Paul Jakmab881c702010-11-23 16:35:42 +00001249 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001250}
1251
1252/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1253 */
Paul Jakmab881c702010-11-23 16:35:42 +00001254static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001255bgp_attr_munge_as4_attrs (struct peer *const peer,
1256 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001257 struct aspath *as4_path, as_t as4_aggregator,
1258 struct in_addr *as4_aggregator_addr)
1259{
1260 int ignore_as4_path = 0;
1261 struct aspath *newpath;
1262 struct attr_extra *attre = attr->extra;
1263
Paul Jakmab881c702010-11-23 16:35:42 +00001264 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001265 {
1266 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1267 * if given.
1268 * It is worth a warning though, because the peer really
1269 * should not send them
1270 */
1271 if (BGP_DEBUG(as4, AS4))
1272 {
1273 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1274 zlog_debug ("[AS4] %s %s AS4_PATH",
1275 peer->host, "AS4 capable peer, yet it sent");
1276
1277 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1278 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1279 peer->host, "AS4 capable peer, yet it sent");
1280 }
1281
Paul Jakmab881c702010-11-23 16:35:42 +00001282 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001283 }
1284
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001285 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1286 * because that may override AS4_PATH
1287 */
1288 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1289 {
Paul Jakmab881c702010-11-23 16:35:42 +00001290 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001291 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001292 assert (attre);
1293
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001294 /* received both.
1295 * if the as_number in aggregator is not AS_TRANS,
1296 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1297 * and the Aggregator shall be taken as
1298 * info on the aggregating node, and the AS_PATH
1299 * shall be taken as the AS_PATH
1300 * otherwise
1301 * the Aggregator shall be ignored and the
1302 * AS4_AGGREGATOR shall be taken as the
1303 * Aggregating node and the AS_PATH is to be
1304 * constructed "as in all other cases"
1305 */
Paul Jakmab881c702010-11-23 16:35:42 +00001306 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001307 {
1308 /* ignore */
1309 if ( BGP_DEBUG(as4, AS4))
1310 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1311 " send AGGREGATOR != AS_TRANS and"
1312 " AS4_AGGREGATOR, so ignore"
1313 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1314 ignore_as4_path = 1;
1315 }
1316 else
1317 {
1318 /* "New_aggregator shall be taken as aggregator" */
1319 attre->aggregator_as = as4_aggregator;
1320 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1321 }
1322 }
1323 else
1324 {
1325 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1326 * That is bogus - but reading the conditions
1327 * we have to handle AS4_AGGREGATOR as if it were
1328 * AGGREGATOR in that case
1329 */
1330 if ( BGP_DEBUG(as4, AS4))
1331 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1332 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1333 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001334 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001335 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1336 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1337 }
1338 }
1339
1340 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001341 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001342 {
1343 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001344 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001345 attr->aspath = aspath_intern (newpath);
1346 }
Paul Jakmab881c702010-11-23 16:35:42 +00001347 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001348}
1349
paul718e3742002-12-13 20:15:29 +00001350/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001351static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001352bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001353{
Paul Jakma835315b2012-01-18 12:28:30 +00001354 struct peer *const peer = args->peer;
1355 struct attr *const attr = args->attr;
1356 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001357
paul718e3742002-12-13 20:15:29 +00001358 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001359 {
1360 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001361 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001362 }
Paul Jakma0c466382010-12-05 17:17:26 +00001363
1364 attr->community =
1365 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1366
1367 /* XXX: fix community_parse to use stream API and remove this */
1368 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001369
Paul Jakma0c466382010-12-05 17:17:26 +00001370 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001371 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001372 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001373 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001374
paul718e3742002-12-13 20:15:29 +00001375 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1376
Paul Jakmab881c702010-11-23 16:35:42 +00001377 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001378}
1379
1380/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001381static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001382bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001383{
Paul Jakma835315b2012-01-18 12:28:30 +00001384 struct peer *const peer = args->peer;
1385 struct attr *const attr = args->attr;
1386 const bgp_size_t length = args->length;
1387
Denis Ovsienkod595b562011-09-30 15:08:54 +04001388 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001389 if (length != 4)
1390 {
1391 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1392
Paul Jakma835315b2012-01-18 12:28:30 +00001393 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001394 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001395 args->total);
paul718e3742002-12-13 20:15:29 +00001396 }
1397
Paul Jakmafb982c22007-05-04 20:15:47 +00001398 (bgp_attr_extra_get (attr))->originator_id.s_addr
1399 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001400
1401 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1402
Paul Jakmab881c702010-11-23 16:35:42 +00001403 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001404}
1405
1406/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001407static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001408bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001409{
Paul Jakma835315b2012-01-18 12:28:30 +00001410 struct peer *const peer = args->peer;
1411 struct attr *const attr = args->attr;
1412 const bgp_size_t length = args->length;
1413
paul718e3742002-12-13 20:15:29 +00001414 /* Check length. */
1415 if (length % 4)
1416 {
1417 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1418
Paul Jakma835315b2012-01-18 12:28:30 +00001419 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1420 args->total);
paul718e3742002-12-13 20:15:29 +00001421 }
1422
Paul Jakmafb982c22007-05-04 20:15:47 +00001423 (bgp_attr_extra_get (attr))->cluster
1424 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001425
1426 /* XXX: Fix cluster_parse to use stream API and then remove this */
1427 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001428
1429 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1430
Paul Jakmab881c702010-11-23 16:35:42 +00001431 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001432}
1433
1434/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001435int
Paul Jakma835315b2012-01-18 12:28:30 +00001436bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1437 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001438{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001439 afi_t afi;
1440 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001441 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001442 size_t start;
paul718e3742002-12-13 20:15:29 +00001443 int ret;
1444 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001445 struct peer *const peer = args->peer;
1446 struct attr *const attr = args->attr;
1447 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001448 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001449
paul718e3742002-12-13 20:15:29 +00001450 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001451 s = BGP_INPUT(peer);
1452 start = stream_get_getp(s);
1453
1454 /* safe to read statically sized header? */
1455#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001456#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001457 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001458 {
1459 zlog_info ("%s: %s sent invalid length, %lu",
1460 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001461 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001462 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001463
paul718e3742002-12-13 20:15:29 +00001464 /* Load AFI, SAFI. */
1465 afi = stream_getw (s);
1466 safi = stream_getc (s);
1467
1468 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001469 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001470
Paul Jakma03292802008-06-07 20:37:10 +00001471 if (LEN_LEFT < attre->mp_nexthop_len)
1472 {
1473 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1474 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001475 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001476 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001477
paul718e3742002-12-13 20:15:29 +00001478 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001479 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001480 {
1481 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001482 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001483 /* Probably needed for RFC 2283 */
1484 if (attr->nexthop.s_addr == 0)
1485 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001486 break;
1487 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001488 stream_getl (s); /* RD high */
1489 stream_getl (s); /* RD low */
1490 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001491 break;
1492#ifdef HAVE_IPV6
1493 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001494 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001495 break;
1496 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001497 stream_get (&attre->mp_nexthop_global, s, 16);
1498 stream_get (&attre->mp_nexthop_local, s, 16);
1499 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001500 {
1501 char buf1[INET6_ADDRSTRLEN];
1502 char buf2[INET6_ADDRSTRLEN];
1503
1504 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001505 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 +00001506 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001507 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001508 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001509 buf2, INET6_ADDRSTRLEN));
1510
Paul Jakmafb982c22007-05-04 20:15:47 +00001511 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001512 }
1513 break;
1514#endif /* HAVE_IPV6 */
1515 default:
Paul Jakma03292802008-06-07 20:37:10 +00001516 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1517 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001518 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001519 }
1520
Paul Jakma03292802008-06-07 20:37:10 +00001521 if (!LEN_LEFT)
1522 {
1523 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1524 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001525 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001526 }
paul718e3742002-12-13 20:15:29 +00001527
Paul Jakma6e4ab122007-04-10 19:36:48 +00001528 {
1529 u_char val;
1530 if ((val = stream_getc (s)))
1531 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1532 peer->host, val);
1533 }
1534
1535 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001536 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001537 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001538 {
1539 zlog_info ("%s: (%s) Failed to read NLRI",
1540 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001541 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001542 }
paul718e3742002-12-13 20:15:29 +00001543
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001544 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001545 {
1546 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001547 if (ret < 0)
1548 {
1549 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1550 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001551 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001552 }
paul718e3742002-12-13 20:15:29 +00001553 }
1554
1555 mp_update->afi = afi;
1556 mp_update->safi = safi;
1557 mp_update->nlri = stream_pnt (s);
1558 mp_update->length = nlri_len;
1559
paul9985f832005-02-09 15:51:56 +00001560 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001561
Paul Jakmab881c702010-11-23 16:35:42 +00001562 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001563#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001564}
1565
1566/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001567int
Paul Jakma835315b2012-01-18 12:28:30 +00001568bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001569 struct bgp_nlri *mp_withdraw)
1570{
1571 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001572 afi_t afi;
1573 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001574 u_int16_t withdraw_len;
1575 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001576 struct peer *const peer = args->peer;
1577 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001578
1579 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001580
1581#define BGP_MP_UNREACH_MIN_SIZE 3
1582 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001583 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001584
paul718e3742002-12-13 20:15:29 +00001585 afi = stream_getw (s);
1586 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001587
1588 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001589
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001590 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001591 {
1592 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1593 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001594 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001595 }
1596
1597 mp_withdraw->afi = afi;
1598 mp_withdraw->safi = safi;
1599 mp_withdraw->nlri = stream_pnt (s);
1600 mp_withdraw->length = withdraw_len;
1601
paul9985f832005-02-09 15:51:56 +00001602 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001603
Paul Jakmab881c702010-11-23 16:35:42 +00001604 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001605}
1606
1607/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001608static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001609bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001610{
Paul Jakma835315b2012-01-18 12:28:30 +00001611 struct peer *const peer = args->peer;
1612 struct attr *const attr = args->attr;
1613 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001614
paul718e3742002-12-13 20:15:29 +00001615 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001616 {
1617 if (attr->extra)
1618 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001619 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001620 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001621 }
Paul Jakma0c466382010-12-05 17:17:26 +00001622
1623 (bgp_attr_extra_get (attr))->ecommunity =
1624 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1625 /* XXX: fix ecommunity_parse to use stream API */
1626 stream_forward_getp (peer->ibuf, length);
1627
1628 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001629 return bgp_attr_malformed (args,
1630 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1631 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001632
paul718e3742002-12-13 20:15:29 +00001633 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1634
Paul Jakmab881c702010-11-23 16:35:42 +00001635 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001636}
1637
1638/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001639static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001640bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001641{
1642 bgp_size_t total;
1643 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001644 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001645 struct peer *const peer = args->peer;
1646 struct attr *const attr = args->attr;
1647 u_char *const startp = args->startp;
1648 const u_char type = args->type;
1649 const u_char flag = args->flags;
1650 const bgp_size_t length = args->length;
1651
paul718e3742002-12-13 20:15:29 +00001652
hassof4184462005-02-01 20:13:16 +00001653 if (BGP_DEBUG (normal, NORMAL))
1654 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1655 peer->host, type, length);
1656
paul718e3742002-12-13 20:15:29 +00001657 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001658 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001659 "Unknown attribute type %d length %d is received", type, length);
1660
1661 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001662 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001663
paul718e3742002-12-13 20:15:29 +00001664 /* If any of the mandatory well-known attributes are not recognized,
1665 then the Error Subcode is set to Unrecognized Well-known
1666 Attribute. The Data field contains the unrecognized attribute
1667 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001668 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001669 {
Paul Jakma835315b2012-01-18 12:28:30 +00001670 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001671 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001672 args->total);
paul718e3742002-12-13 20:15:29 +00001673 }
1674
1675 /* Unrecognized non-transitive optional attributes must be quietly
1676 ignored and not passed along to other BGP peers. */
1677 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001678 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001679
1680 /* If a path with recognized transitive optional attribute is
1681 accepted and passed along to other BGP peers and the Partial bit
1682 in the Attribute Flags octet is set to 1 by some previous AS, it
1683 is not set back to 0 by the current AS. */
1684 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1685
1686 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001687 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001688 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001689
Paul Jakmafb982c22007-05-04 20:15:47 +00001690 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001691
1692 if (transit->val)
1693 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1694 transit->length + total);
1695 else
1696 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1697
1698 memcpy (transit->val + transit->length, startp, total);
1699 transit->length += total;
1700
Paul Jakmab881c702010-11-23 16:35:42 +00001701 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001702}
1703
1704/* Read attribute of update packet. This function is called from
1705 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001706bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001707bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1708 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1709{
1710 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001711 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001712 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001713 bgp_size_t length;
1714 u_char *startp, *endp;
1715 u_char *attr_endp;
1716 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001717 /* we need the as4_path only until we have synthesized the as_path with it */
1718 /* same goes for as4_aggregator */
1719 struct aspath *as4_path = NULL;
1720 as_t as4_aggregator = 0;
1721 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001722
1723 /* Initialize bitmap. */
1724 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1725
1726 /* End pointer of BGP attribute. */
1727 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001728
paul718e3742002-12-13 20:15:29 +00001729 /* Get attributes to the end of attribute length. */
1730 while (BGP_INPUT_PNT (peer) < endp)
1731 {
1732 /* Check remaining length check.*/
1733 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1734 {
gdtc29fdba2004-12-09 14:46:46 +00001735 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001736 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001737 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001738 peer->host,
1739 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001740
1741 bgp_notify_send (peer,
1742 BGP_NOTIFY_UPDATE_ERR,
1743 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001744 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001745 }
1746
1747 /* Fetch attribute flag and type. */
1748 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001749 /* "The lower-order four bits of the Attribute Flags octet are
1750 unused. They MUST be zero when sent and MUST be ignored when
1751 received." */
1752 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001753 type = stream_getc (BGP_INPUT (peer));
1754
Paul Jakma370b64a2007-12-22 16:49:52 +00001755 /* Check whether Extended-Length applies and is in bounds */
1756 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1757 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1758 {
1759 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001760 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001761 peer->host,
1762 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1763
1764 bgp_notify_send (peer,
1765 BGP_NOTIFY_UPDATE_ERR,
1766 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001767 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001768 }
Paul Jakma835315b2012-01-18 12:28:30 +00001769
paul718e3742002-12-13 20:15:29 +00001770 /* Check extended attribue length bit. */
1771 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1772 length = stream_getw (BGP_INPUT (peer));
1773 else
1774 length = stream_getc (BGP_INPUT (peer));
1775
1776 /* If any attribute appears more than once in the UPDATE
1777 message, then the Error Subcode is set to Malformed Attribute
1778 List. */
1779
1780 if (CHECK_BITMAP (seen, type))
1781 {
1782 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001783 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001784 peer->host, type);
1785
1786 bgp_notify_send (peer,
1787 BGP_NOTIFY_UPDATE_ERR,
1788 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001789 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001790 }
1791
1792 /* Set type to bitmap to check duplicate attribute. `type' is
1793 unsigned char so it never overflow bitmap range. */
1794
1795 SET_BITMAP (seen, type);
1796
1797 /* Overflow check. */
1798 attr_endp = BGP_INPUT_PNT (peer) + length;
1799
1800 if (attr_endp > endp)
1801 {
1802 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001803 "%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 +00001804 bgp_notify_send (peer,
1805 BGP_NOTIFY_UPDATE_ERR,
1806 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001807 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001808 }
Paul Jakma835315b2012-01-18 12:28:30 +00001809
1810 struct bgp_attr_parser_args attr_args = {
1811 .peer = peer,
1812 .length = length,
1813 .attr = attr,
1814 .type = type,
1815 .flags = flag,
1816 .startp = startp,
1817 .total = attr_endp - startp,
1818 };
1819
1820
1821 /* If any recognized attribute has Attribute Flags that conflict
1822 with the Attribute Type Code, then the Error Subcode is set to
1823 Attribute Flags Error. The Data field contains the erroneous
1824 attribute (type, length and value). */
1825 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001826 {
1827 bgp_attr_parse_ret_t ret;
1828 ret = bgp_attr_malformed (&attr_args,
1829 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1830 attr_args.total);
1831 if (ret == BGP_ATTR_PARSE_PROCEED)
1832 continue;
1833 return ret;
1834 }
paul718e3742002-12-13 20:15:29 +00001835
1836 /* OK check attribute and store it's value. */
1837 switch (type)
1838 {
1839 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001840 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001841 break;
1842 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001843 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001844 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001845 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001846 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001847 break;
paul718e3742002-12-13 20:15:29 +00001848 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001849 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001850 break;
1851 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001852 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001853 break;
1854 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001855 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001856 break;
1857 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001858 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001859 break;
1860 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001861 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001862 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001863 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001864 ret = bgp_attr_as4_aggregator (&attr_args,
1865 &as4_aggregator,
1866 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001867 break;
paul718e3742002-12-13 20:15:29 +00001868 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001869 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001870 break;
1871 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001872 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001873 break;
1874 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001875 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001876 break;
1877 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001878 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001879 break;
1880 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001881 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001882 break;
1883 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001884 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001885 break;
1886 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001887 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001888 break;
1889 }
Paul Jakmab881c702010-11-23 16:35:42 +00001890
1891 /* If hard error occured immediately return to the caller. */
1892 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001893 {
1894 zlog (peer->log, LOG_WARNING,
1895 "%s: Attribute %s, parse error",
1896 peer->host,
1897 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001898 bgp_notify_send (peer,
1899 BGP_NOTIFY_UPDATE_ERR,
1900 BGP_NOTIFY_UPDATE_MAL_ATTR);
1901 if (as4_path)
1902 aspath_unintern (&as4_path);
1903 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001904 }
Paul Jakmab881c702010-11-23 16:35:42 +00001905 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1906 {
1907
1908 zlog (peer->log, LOG_WARNING,
1909 "%s: Attribute %s, parse error - treating as withdrawal",
1910 peer->host,
1911 LOOKUP (attr_str, type));
1912 if (as4_path)
1913 aspath_unintern (&as4_path);
1914 return ret;
1915 }
1916
paul718e3742002-12-13 20:15:29 +00001917 /* Check the fetched length. */
1918 if (BGP_INPUT_PNT (peer) != attr_endp)
1919 {
1920 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001921 "%s: BGP attribute %s, fetch error",
1922 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001923 bgp_notify_send (peer,
1924 BGP_NOTIFY_UPDATE_ERR,
1925 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001926 if (as4_path)
1927 aspath_unintern (&as4_path);
1928 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001929 }
1930 }
1931
1932 /* Check final read pointer is same as end pointer. */
1933 if (BGP_INPUT_PNT (peer) != endp)
1934 {
1935 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001936 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001937 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001938 bgp_notify_send (peer,
1939 BGP_NOTIFY_UPDATE_ERR,
1940 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001941 if (as4_path)
1942 aspath_unintern (&as4_path);
1943 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001944 }
1945
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001946 /*
1947 * At this place we can see whether we got AS4_PATH and/or
1948 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1949 * We can not do this before we've read all attributes because
1950 * the as4 handling does not say whether AS4_PATH has to be sent
1951 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1952 * in relationship to AGGREGATOR.
1953 * So, to be defensive, we are not relying on any order and read
1954 * all attributes first, including these 32bit ones, and now,
1955 * afterwards, we look what and if something is to be done for as4.
1956 */
Paul Jakma835315b2012-01-18 12:28:30 +00001957 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001958 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001959 {
1960 if (as4_path)
1961 aspath_unintern (&as4_path);
1962 return BGP_ATTR_PARSE_ERROR;
1963 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001964
1965 /* At this stage, we have done all fiddling with as4, and the
1966 * resulting info is in attr->aggregator resp. attr->aspath
1967 * so we can chuck as4_aggregator and as4_path alltogether in
1968 * order to save memory
1969 */
Paul Jakmab881c702010-11-23 16:35:42 +00001970 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001971 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001972 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001973 /* The flag that we got this is still there, but that does not
1974 * do any trouble
1975 */
1976 }
1977 /*
1978 * The "rest" of the code does nothing with as4_aggregator.
1979 * there is no memory attached specifically which is not part
1980 * of the attr.
1981 * so ignoring just means do nothing.
1982 */
1983 /*
1984 * Finally do the checks on the aspath we did not do yet
1985 * because we waited for a potentially synthesized aspath.
1986 */
Paul Jakmab881c702010-11-23 16:35:42 +00001987 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001988 {
Paul Jakma835315b2012-01-18 12:28:30 +00001989 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001990 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001991 return ret;
1992 }
1993
paul718e3742002-12-13 20:15:29 +00001994 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001995 if (attr->extra && attr->extra->transit)
1996 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001997
Paul Jakmab881c702010-11-23 16:35:42 +00001998 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001999}
2000
2001/* Well-known attribute check. */
2002int
2003bgp_attr_check (struct peer *peer, struct attr *attr)
2004{
2005 u_char type = 0;
2006
2007 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2008 type = BGP_ATTR_ORIGIN;
2009
2010 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2011 type = BGP_ATTR_AS_PATH;
2012
2013 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2014 type = BGP_ATTR_NEXT_HOP;
2015
2016 if (peer_sort (peer) == BGP_PEER_IBGP
2017 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2018 type = BGP_ATTR_LOCAL_PREF;
2019
2020 if (type)
2021 {
2022 zlog (peer->log, LOG_WARNING,
2023 "%s Missing well-known attribute %d.",
2024 peer->host, type);
2025 bgp_notify_send_with_data (peer,
2026 BGP_NOTIFY_UPDATE_ERR,
2027 BGP_NOTIFY_UPDATE_MISS_ATTR,
2028 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002029 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002030 }
Paul Jakmab881c702010-11-23 16:35:42 +00002031 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002032}
2033
2034int stream_put_prefix (struct stream *, struct prefix *);
2035
2036/* Make attribute packet. */
2037bgp_size_t
2038bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2039 struct stream *s, struct attr *attr, struct prefix *p,
2040 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002041 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002042{
paulfe69a502005-09-10 16:55:02 +00002043 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002044 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002045 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002046 int send_as4_path = 0;
2047 int send_as4_aggregator = 0;
2048 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002049
2050 if (! bgp)
2051 bgp = bgp_get_default ();
2052
2053 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002054 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002055
2056 /* Origin attribute. */
2057 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2058 stream_putc (s, BGP_ATTR_ORIGIN);
2059 stream_putc (s, 1);
2060 stream_putc (s, attr->origin);
2061
2062 /* AS path attribute. */
2063
2064 /* If remote-peer is EBGP */
2065 if (peer_sort (peer) == BGP_PEER_EBGP
2066 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002067 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002068 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002069 {
2070 aspath = aspath_dup (attr->aspath);
2071
2072 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2073 {
2074 /* Strip the confed info, and then stuff our path CONFED_ID
2075 on the front */
2076 aspath = aspath_delete_confed_seq (aspath);
2077 aspath = aspath_add_seq (aspath, bgp->confed_id);
2078 }
2079 else
2080 {
2081 aspath = aspath_add_seq (aspath, peer->local_as);
2082 if (peer->change_local_as)
2083 aspath = aspath_add_seq (aspath, peer->change_local_as);
2084 }
2085 }
2086 else if (peer_sort (peer) == BGP_PEER_CONFED)
2087 {
2088 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2089 aspath = aspath_dup (attr->aspath);
2090 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2091 }
2092 else
2093 aspath = attr->aspath;
2094
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002095 /* If peer is not AS4 capable, then:
2096 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2097 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2098 * types are in it (i.e. exclude them if they are there)
2099 * AND do this only if there is at least one asnum > 65535 in the path!
2100 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2101 * all ASnums > 65535 to BGP_AS_TRANS
2102 */
paul718e3742002-12-13 20:15:29 +00002103
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002104 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2105 stream_putc (s, BGP_ATTR_AS_PATH);
2106 aspath_sizep = stream_get_endp (s);
2107 stream_putw (s, 0);
2108 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2109
2110 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2111 * in the path
2112 */
2113 if (!use32bit && aspath_has_as4 (aspath))
2114 send_as4_path = 1; /* we'll do this later, at the correct place */
2115
paul718e3742002-12-13 20:15:29 +00002116 /* Nexthop attribute. */
2117 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2118 {
2119 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2120 stream_putc (s, BGP_ATTR_NEXT_HOP);
2121 stream_putc (s, 4);
2122 if (safi == SAFI_MPLS_VPN)
2123 {
2124 if (attr->nexthop.s_addr == 0)
2125 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2126 else
2127 stream_put_ipv4 (s, attr->nexthop.s_addr);
2128 }
2129 else
2130 stream_put_ipv4 (s, attr->nexthop.s_addr);
2131 }
2132
2133 /* MED attribute. */
2134 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2135 {
2136 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2137 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2138 stream_putc (s, 4);
2139 stream_putl (s, attr->med);
2140 }
2141
2142 /* Local preference. */
2143 if (peer_sort (peer) == BGP_PEER_IBGP ||
2144 peer_sort (peer) == BGP_PEER_CONFED)
2145 {
2146 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2147 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2148 stream_putc (s, 4);
2149 stream_putl (s, attr->local_pref);
2150 }
2151
2152 /* Atomic aggregate. */
2153 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2154 {
2155 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2156 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2157 stream_putc (s, 0);
2158 }
2159
2160 /* Aggregator. */
2161 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2162 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002163 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002164
2165 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002166 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2167 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002168
2169 if (use32bit)
2170 {
2171 /* AS4 capable peer */
2172 stream_putc (s, 8);
2173 stream_putl (s, attr->extra->aggregator_as);
2174 }
2175 else
2176 {
2177 /* 2-byte AS peer */
2178 stream_putc (s, 6);
2179
2180 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2181 if ( attr->extra->aggregator_as > 65535 )
2182 {
2183 stream_putw (s, BGP_AS_TRANS);
2184
2185 /* we have to send AS4_AGGREGATOR, too.
2186 * we'll do that later in order to send attributes in ascending
2187 * order.
2188 */
2189 send_as4_aggregator = 1;
2190 }
2191 else
2192 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2193 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002194 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002195 }
2196
2197 /* Community attribute. */
2198 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2199 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2200 {
2201 if (attr->community->size * 4 > 255)
2202 {
2203 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2204 stream_putc (s, BGP_ATTR_COMMUNITIES);
2205 stream_putw (s, attr->community->size * 4);
2206 }
2207 else
2208 {
2209 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2210 stream_putc (s, BGP_ATTR_COMMUNITIES);
2211 stream_putc (s, attr->community->size * 4);
2212 }
2213 stream_put (s, attr->community->val, attr->community->size * 4);
2214 }
2215
2216 /* Route Reflector. */
2217 if (peer_sort (peer) == BGP_PEER_IBGP
2218 && from
2219 && peer_sort (from) == BGP_PEER_IBGP)
2220 {
2221 /* Originator ID. */
2222 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2223 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2224 stream_putc (s, 4);
2225
2226 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002227 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002228 else
2229 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002230
2231 /* Cluster list. */
2232 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2233 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2234
Paul Jakma9eda90c2007-08-30 13:36:17 +00002235 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002236 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002237 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002238 /* If this peer configuration's parent BGP has cluster_id. */
2239 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2240 stream_put_in_addr (s, &bgp->cluster_id);
2241 else
2242 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002243 stream_put (s, attr->extra->cluster->list,
2244 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002245 }
2246 else
2247 {
2248 stream_putc (s, 4);
2249 /* If this peer configuration's parent BGP has cluster_id. */
2250 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2251 stream_put_in_addr (s, &bgp->cluster_id);
2252 else
2253 stream_put_in_addr (s, &bgp->router_id);
2254 }
2255 }
2256
2257#ifdef HAVE_IPV6
2258 /* If p is IPv6 address put it into attribute. */
2259 if (p->family == AF_INET6)
2260 {
2261 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002262 struct attr_extra *attre = attr->extra;
2263
2264 assert (attr->extra);
2265
paul718e3742002-12-13 20:15:29 +00002266 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2267 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002268 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002269 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002270 stream_putw (s, AFI_IP6); /* AFI */
2271 stream_putc (s, safi); /* SAFI */
2272
Paul Jakmafb982c22007-05-04 20:15:47 +00002273 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002274
Paul Jakmafb982c22007-05-04 20:15:47 +00002275 if (attre->mp_nexthop_len == 16)
2276 stream_put (s, &attre->mp_nexthop_global, 16);
2277 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002278 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002279 stream_put (s, &attre->mp_nexthop_global, 16);
2280 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002281 }
2282
2283 /* SNPA */
2284 stream_putc (s, 0);
2285
paul718e3742002-12-13 20:15:29 +00002286 /* Prefix write. */
2287 stream_put_prefix (s, p);
2288
2289 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002290 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002291 }
2292#endif /* HAVE_IPV6 */
2293
2294 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2295 {
2296 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002297
2298 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2299 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002300 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002301 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002302 stream_putw (s, AFI_IP); /* AFI */
2303 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2304
2305 stream_putc (s, 4);
2306 stream_put_ipv4 (s, attr->nexthop.s_addr);
2307
2308 /* SNPA */
2309 stream_putc (s, 0);
2310
paul718e3742002-12-13 20:15:29 +00002311 /* Prefix write. */
2312 stream_put_prefix (s, p);
2313
2314 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002315 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002316 }
2317
2318 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2319 {
2320 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002321
2322 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2323 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002324 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002325 stream_putc (s, 0); /* Length of this attribute. */
2326 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002327 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002328
2329 stream_putc (s, 12);
2330 stream_putl (s, 0);
2331 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002332 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002333
2334 /* SNPA */
2335 stream_putc (s, 0);
2336
paul718e3742002-12-13 20:15:29 +00002337 /* Tag, RD, Prefix write. */
2338 stream_putc (s, p->prefixlen + 88);
2339 stream_put (s, tag, 3);
2340 stream_put (s, prd->val, 8);
2341 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2342
2343 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002344 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002345 }
2346
2347 /* Extended Communities attribute. */
2348 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2349 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2350 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002351 struct attr_extra *attre = attr->extra;
2352
2353 assert (attre);
2354
2355 if (peer_sort (peer) == BGP_PEER_IBGP
2356 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002357 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002358 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002359 {
2360 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2361 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002362 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002363 }
2364 else
2365 {
2366 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2367 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002368 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002369 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002370 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002371 }
2372 else
2373 {
paul5228ad22004-06-04 17:58:18 +00002374 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002375 int tbit;
2376 int ecom_tr_size = 0;
2377 int i;
2378
Paul Jakmafb982c22007-05-04 20:15:47 +00002379 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002380 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002381 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002382 tbit = *pnt;
2383
2384 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2385 continue;
2386
2387 ecom_tr_size++;
2388 }
2389
2390 if (ecom_tr_size)
2391 {
2392 if (ecom_tr_size * 8 > 255)
2393 {
2394 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2395 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2396 stream_putw (s, ecom_tr_size * 8);
2397 }
2398 else
2399 {
2400 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2401 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2402 stream_putc (s, ecom_tr_size * 8);
2403 }
2404
Paul Jakmafb982c22007-05-04 20:15:47 +00002405 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002406 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002407 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002408 tbit = *pnt;
2409
2410 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2411 continue;
2412
2413 stream_put (s, pnt, 8);
2414 }
2415 }
paul718e3742002-12-13 20:15:29 +00002416 }
paul718e3742002-12-13 20:15:29 +00002417 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002418
2419 if ( send_as4_path )
2420 {
2421 /* If the peer is NOT As4 capable, AND */
2422 /* there are ASnums > 65535 in path THEN
2423 * give out AS4_PATH */
2424
2425 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2426 * path segments!
2427 * Hm, I wonder... confederation things *should* only be at
2428 * the beginning of an aspath, right? Then we should use
2429 * aspath_delete_confed_seq for this, because it is already
2430 * there! (JK)
2431 * Folks, talk to me: what is reasonable here!?
2432 */
2433 aspath = aspath_delete_confed_seq (aspath);
2434
2435 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2436 stream_putc (s, BGP_ATTR_AS4_PATH);
2437 aspath_sizep = stream_get_endp (s);
2438 stream_putw (s, 0);
2439 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2440 }
2441
2442 if (aspath != attr->aspath)
2443 aspath_free (aspath);
2444
2445 if ( send_as4_aggregator )
2446 {
2447 assert (attr->extra);
2448
2449 /* send AS4_AGGREGATOR, at this place */
2450 /* this section of code moved here in order to ensure the correct
2451 * *ascending* order of attributes
2452 */
2453 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2454 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2455 stream_putc (s, 8);
2456 stream_putl (s, attr->extra->aggregator_as);
2457 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2458 }
Paul Jakma41367172007-08-06 15:24:51 +00002459
paul718e3742002-12-13 20:15:29 +00002460 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002461 if (attr->extra && attr->extra->transit)
2462 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002463
2464 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002465 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002466}
2467
2468bgp_size_t
2469bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2470 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002471 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002472{
2473 unsigned long cp;
2474 unsigned long attrlen_pnt;
2475 bgp_size_t size;
2476
paul9985f832005-02-09 15:51:56 +00002477 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002478
2479 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2480 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2481
paul9985f832005-02-09 15:51:56 +00002482 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002483 stream_putc (s, 0); /* Length of this attribute. */
2484
2485 stream_putw (s, family2afi (p->family));
2486
2487 if (safi == SAFI_MPLS_VPN)
2488 {
2489 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002490 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002491
2492 /* prefix. */
2493 stream_putc (s, p->prefixlen + 88);
2494 stream_put (s, tag, 3);
2495 stream_put (s, prd->val, 8);
2496 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2497 }
2498 else
2499 {
2500 /* SAFI */
2501 stream_putc (s, safi);
2502
2503 /* prefix */
2504 stream_put_prefix (s, p);
2505 }
2506
2507 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002508 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002509 stream_putc_at (s, attrlen_pnt, size);
2510
paul9985f832005-02-09 15:51:56 +00002511 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002512}
2513
2514/* Initialization of attribute. */
2515void
paulfe69a502005-09-10 16:55:02 +00002516bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002517{
paul718e3742002-12-13 20:15:29 +00002518 aspath_init ();
2519 attrhash_init ();
2520 community_init ();
2521 ecommunity_init ();
2522 cluster_init ();
2523 transit_init ();
2524}
2525
Chris Caputo228da422009-07-18 05:44:03 +00002526void
2527bgp_attr_finish (void)
2528{
2529 aspath_finish ();
2530 attrhash_finish ();
2531 community_finish ();
2532 ecommunity_finish ();
2533 cluster_finish ();
2534 transit_finish ();
2535}
2536
paul718e3742002-12-13 20:15:29 +00002537/* Make attribute packet. */
2538void
paula3845922003-10-18 01:30:50 +00002539bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2540 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002541{
2542 unsigned long cp;
2543 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002544 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002545 struct aspath *aspath;
2546
2547 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002548 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002549
2550 /* Place holder of length. */
2551 stream_putw (s, 0);
2552
2553 /* Origin attribute. */
2554 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2555 stream_putc (s, BGP_ATTR_ORIGIN);
2556 stream_putc (s, 1);
2557 stream_putc (s, attr->origin);
2558
2559 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002560
2561 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2562 stream_putc (s, BGP_ATTR_AS_PATH);
2563 aspath_lenp = stream_get_endp (s);
2564 stream_putw (s, 0);
2565
2566 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002567
2568 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002569 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2570 if(prefix != NULL
2571#ifdef HAVE_IPV6
2572 && prefix->family != AF_INET6
2573#endif /* HAVE_IPV6 */
2574 )
2575 {
2576 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2577 stream_putc (s, BGP_ATTR_NEXT_HOP);
2578 stream_putc (s, 4);
2579 stream_put_ipv4 (s, attr->nexthop.s_addr);
2580 }
paul718e3742002-12-13 20:15:29 +00002581
2582 /* MED attribute. */
2583 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2584 {
2585 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2586 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2587 stream_putc (s, 4);
2588 stream_putl (s, attr->med);
2589 }
2590
2591 /* Local preference. */
2592 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2593 {
2594 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2595 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2596 stream_putc (s, 4);
2597 stream_putl (s, attr->local_pref);
2598 }
2599
2600 /* Atomic aggregate. */
2601 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2602 {
2603 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2604 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2605 stream_putc (s, 0);
2606 }
2607
2608 /* Aggregator. */
2609 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2610 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002611 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002612 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2613 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002614 stream_putc (s, 8);
2615 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002616 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002617 }
2618
2619 /* Community attribute. */
2620 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2621 {
2622 if (attr->community->size * 4 > 255)
2623 {
2624 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2625 stream_putc (s, BGP_ATTR_COMMUNITIES);
2626 stream_putw (s, attr->community->size * 4);
2627 }
2628 else
2629 {
2630 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2631 stream_putc (s, BGP_ATTR_COMMUNITIES);
2632 stream_putc (s, attr->community->size * 4);
2633 }
2634 stream_put (s, attr->community->val, attr->community->size * 4);
2635 }
2636
paula3845922003-10-18 01:30:50 +00002637#ifdef HAVE_IPV6
2638 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002639 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2640 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002641 {
2642 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002643 struct attr_extra *attre = attr->extra;
2644
paula3845922003-10-18 01:30:50 +00002645 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2646 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002647 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002648
2649 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002650 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002651 stream_putw(s, AFI_IP6); /* AFI */
2652 stream_putc(s, SAFI_UNICAST); /* SAFI */
2653
2654 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002655 stream_putc(s, attre->mp_nexthop_len);
2656 stream_put(s, &attre->mp_nexthop_global, 16);
2657 if (attre->mp_nexthop_len == 32)
2658 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002659
2660 /* SNPA */
2661 stream_putc(s, 0);
2662
2663 /* Prefix */
2664 stream_put_prefix(s, prefix);
2665
2666 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002667 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002668 }
2669#endif /* HAVE_IPV6 */
2670
paul718e3742002-12-13 20:15:29 +00002671 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002672 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002673 stream_putw_at (s, cp, len);
2674}