blob: b02cfee356cc43e176d7a4df8312d63da9815934 [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 */
722 u_char *startp = (length > 0 ? args->startp : NULL);
723
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,
728 startp, length);
729 return BGP_ATTR_PARSE_ERROR;
730
731 }
732
Paul Jakma835315b2012-01-18 12:28:30 +0000733 switch (args->type) {
Paul Jakmab881c702010-11-23 16:35:42 +0000734 /* where an optional attribute is inconsequential, e.g. it does not affect
735 * route selection, and can be safely ignored then any such attributes
736 * which are malformed should just be ignored and the route processed as
737 * normal.
738 */
739 case BGP_ATTR_AS4_AGGREGATOR:
740 case BGP_ATTR_AGGREGATOR:
741 case BGP_ATTR_ATOMIC_AGGREGATE:
742 return BGP_ATTR_PARSE_PROCEED;
743
744 /* Core attributes, particularly ones which may influence route
745 * selection should always cause session resets
746 */
747 case BGP_ATTR_ORIGIN:
748 case BGP_ATTR_AS_PATH:
749 case BGP_ATTR_NEXT_HOP:
750 case BGP_ATTR_MULTI_EXIT_DISC:
751 case BGP_ATTR_LOCAL_PREF:
752 case BGP_ATTR_COMMUNITIES:
753 case BGP_ATTR_ORIGINATOR_ID:
754 case BGP_ATTR_CLUSTER_LIST:
755 case BGP_ATTR_MP_REACH_NLRI:
756 case BGP_ATTR_MP_UNREACH_NLRI:
757 case BGP_ATTR_EXT_COMMUNITIES:
758 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
759 startp, length);
760 return BGP_ATTR_PARSE_ERROR;
761 }
762
763 /* Partial optional attributes that are malformed should not cause
764 * the whole session to be reset. Instead treat it as a withdrawal
765 * of the routes, if possible.
766 */
Paul Jakma835315b2012-01-18 12:28:30 +0000767 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
768 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
769 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000770 return BGP_ATTR_PARSE_WITHDRAW;
771
772 /* default to reset */
773 return BGP_ATTR_PARSE_ERROR;
774}
775
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400776/* Find out what is wrong with the path attribute flag bits and log the error.
777 "Flag bits" here stand for Optional, Transitive and Partial, but not for
778 Extended Length. Checking O/T/P bits at once implies, that the attribute
779 being diagnosed is defined by RFC as either a "well-known" or an "optional,
780 non-transitive" attribute. */
781static void
Paul Jakma835315b2012-01-18 12:28:30 +0000782bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
783 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400784)
785{
786 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000787 u_char real_flags = args->flags;
788 const u_int8_t attr_code = args->type;
789
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400790 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
791 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
792 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
793 if
794 (
795 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
796 CHECK_FLAG (real_flags, attr_flag_str[i].key)
797 )
798 {
Paul Jakma835315b2012-01-18 12:28:30 +0000799 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400800 LOOKUP (attr_str, attr_code),
801 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
802 attr_flag_str[i].str);
803 seen = 1;
804 }
805 assert (seen);
806}
807
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000808/* Required flags for attributes. EXTLEN will be masked off when testing,
809 * as will PARTIAL for optional+transitive attributes.
810 */
811const u_int8_t attr_flags_values [] = {
812 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
813 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
814 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
815 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
816 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
817 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
818 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
819 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
820 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
821 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
822 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
823 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
824 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
825 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
826 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
827};
828static const size_t attr_flags_values_max =
829 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
830
831static int
Paul Jakma835315b2012-01-18 12:28:30 +0000832bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000833{
834 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000835 const u_int8_t flags = args->flags;
836 const u_int8_t attr_code = args->type;
837 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000838
839 /* there may be attributes we don't know about */
840 if (attr_code > attr_flags_values_max)
841 return 0;
842 if (attr_flags_values[attr_code] == 0)
843 return 0;
844
845 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
846 * 1."
847 */
848 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
849 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
850 {
851 zlog (peer->log, LOG_ERR,
852 "%s well-known attributes must have transitive flag set (%x)",
853 LOOKUP (attr_str, attr_code), flags);
854 return 1;
855 }
856
857 /* "For well-known attributes and for optional non-transitive attributes,
858 * the Partial bit MUST be set to 0."
859 */
860 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
861 {
862 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
863 {
864 zlog (peer->log, LOG_ERR,
865 "%s well-known attribute "
866 "must NOT have the partial flag set (%x)",
867 LOOKUP (attr_str, attr_code), flags);
868 return 1;
869 }
870 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
871 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
872 {
873 zlog (peer->log, LOG_ERR,
874 "%s optional + transitive attribute "
875 "must NOT have the partial flag set (%x)",
876 LOOKUP (attr_str, attr_code), flags);
877 return 1;
878 }
879 }
880
881 /* Optional transitive attributes may go through speakers that don't
882 * reocgnise them and set the Partial bit.
883 */
884 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
885 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
886 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
887
888 if ((flags & ~attr_flags_values[attr_code])
889 == attr_flags_values[attr_code])
890 return 0;
891
Paul Jakma835315b2012-01-18 12:28:30 +0000892 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000893 return 1;
894}
895
paul718e3742002-12-13 20:15:29 +0000896/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000897static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000898bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000899{
Paul Jakma835315b2012-01-18 12:28:30 +0000900 struct peer *const peer = args->peer;
901 struct attr *const attr = args->attr;
902 const bgp_size_t length = args->length;
903
paul718e3742002-12-13 20:15:29 +0000904 /* If any recognized attribute has Attribute Length that conflicts
905 with the expected length (based on the attribute type code), then
906 the Error Subcode is set to Attribute Length Error. The Data
907 field contains the erroneous attribute (type, length and
908 value). */
909 if (length != 1)
910 {
911 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
912 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000913 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000914 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000915 args->total);
paul718e3742002-12-13 20:15:29 +0000916 }
917
918 /* Fetch origin attribute. */
919 attr->origin = stream_getc (BGP_INPUT (peer));
920
921 /* If the ORIGIN attribute has an undefined value, then the Error
922 Subcode is set to Invalid Origin Attribute. The Data field
923 contains the unrecognized attribute (type, length and value). */
924 if ((attr->origin != BGP_ORIGIN_IGP)
925 && (attr->origin != BGP_ORIGIN_EGP)
926 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
927 {
928 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
929 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000930 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000931 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000932 args->total);
paul718e3742002-12-13 20:15:29 +0000933 }
934
935 /* Set oring attribute flag. */
936 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
937
938 return 0;
939}
Paul Jakmaab005292010-11-27 22:48:34 +0000940
941/* Parse AS path information. This function is wrapper of
942 aspath_parse. */
943static int
Paul Jakma835315b2012-01-18 12:28:30 +0000944bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000945{
Paul Jakma835315b2012-01-18 12:28:30 +0000946 struct attr *const attr = args->attr;
947 struct peer *const peer = args->peer;
948 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000949
Paul Jakmaab005292010-11-27 22:48:34 +0000950 /*
951 * peer with AS4 => will get 4Byte ASnums
952 * otherwise, will get 16 Bit
953 */
954 attr->aspath = aspath_parse (peer->ibuf, length,
955 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
956
957 /* In case of IBGP, length will be zero. */
958 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000959 {
Paul Jakmab881c702010-11-23 16:35:42 +0000960 zlog (peer->log, LOG_ERR,
961 "Malformed AS path from %s, length is %d",
962 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000963 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000964 }
Chris Hallcddb8112010-08-09 22:31:37 +0400965
Paul Jakmaab005292010-11-27 22:48:34 +0000966 /* Set aspath attribute flag. */
967 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000968
Paul Jakmab881c702010-11-23 16:35:42 +0000969 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000970}
971
Paul Jakmab881c702010-11-23 16:35:42 +0000972static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000973bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000974{
975 /* These checks were part of bgp_attr_aspath, but with
976 * as4 we should to check aspath things when
977 * aspath synthesizing with as4_path has already taken place.
978 * Otherwise we check ASPATH and use the synthesized thing, and that is
979 * not right.
980 * So do the checks later, i.e. here
981 */
982 struct bgp *bgp = peer->bgp;
983 struct aspath *aspath;
984
paul718e3742002-12-13 20:15:29 +0000985 bgp = peer->bgp;
986
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300987 /* Confederation sanity check. */
988 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
989 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
990 {
991 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +0000992 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
993 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
994 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300995 }
996
paul718e3742002-12-13 20:15:29 +0000997 /* First AS check for EBGP. */
998 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
999 {
1000 if (peer_sort (peer) == BGP_PEER_EBGP
1001 && ! aspath_firstas_check (attr->aspath, peer->as))
1002 {
1003 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001004 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001005 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1006 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1007 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001008 }
1009 }
1010
1011 /* local-as prepend */
1012 if (peer->change_local_as &&
1013 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1014 {
1015 aspath = aspath_dup (attr->aspath);
1016 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001017 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001018 attr->aspath = aspath_intern (aspath);
1019 }
1020
Paul Jakmab881c702010-11-23 16:35:42 +00001021 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001022}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001023
Paul Jakmaab005292010-11-27 22:48:34 +00001024/* Parse AS4 path information. This function is another wrapper of
1025 aspath_parse. */
1026static int
Paul Jakma835315b2012-01-18 12:28:30 +00001027bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001028{
Paul Jakma835315b2012-01-18 12:28:30 +00001029 struct peer *const peer = args->peer;
1030 struct attr *const attr = args->attr;
1031 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001032
Paul Jakmaab005292010-11-27 22:48:34 +00001033 *as4_path = aspath_parse (peer->ibuf, length, 1);
1034
Paul Jakmab881c702010-11-23 16:35:42 +00001035 /* In case of IBGP, length will be zero. */
1036 if (!*as4_path)
1037 {
1038 zlog (peer->log, LOG_ERR,
1039 "Malformed AS4 path from %s, length is %d",
1040 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001041 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001042 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001043 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001044 }
1045
Paul Jakmaab005292010-11-27 22:48:34 +00001046 /* Set aspath attribute flag. */
1047 if (as4_path)
1048 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1049
Paul Jakmab881c702010-11-23 16:35:42 +00001050 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001051}
1052
paul718e3742002-12-13 20:15:29 +00001053/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001054static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001055bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001056{
Paul Jakma835315b2012-01-18 12:28:30 +00001057 struct peer *const peer = args->peer;
1058 struct attr *const attr = args->attr;
1059 const bgp_size_t length = args->length;
1060
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001061 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001062
paul718e3742002-12-13 20:15:29 +00001063 /* Check nexthop attribute length. */
1064 if (length != 4)
1065 {
1066 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1067 length);
1068
Paul Jakma835315b2012-01-18 12:28:30 +00001069 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001070 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001071 args->total);
paul718e3742002-12-13 20:15:29 +00001072 }
1073
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001074 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1075 attribute must result in a NOTIFICATION message (this is implemented below).
1076 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1077 logged locally (this is implemented somewhere else). The UPDATE message
1078 gets ignored in any of these cases. */
1079 nexthop_n = stream_get_ipv4 (peer->ibuf);
1080 nexthop_h = ntohl (nexthop_n);
1081 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1082 {
1083 char buf[INET_ADDRSTRLEN];
1084 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1085 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001086 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001087 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001088 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001089 }
1090
1091 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001092 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1093
Paul Jakmab881c702010-11-23 16:35:42 +00001094 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001095}
1096
1097/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001098static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001099bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001100{
Paul Jakma835315b2012-01-18 12:28:30 +00001101 struct peer *const peer = args->peer;
1102 struct attr *const attr = args->attr;
1103 const bgp_size_t length = args->length;
1104
paul718e3742002-12-13 20:15:29 +00001105 /* Length check. */
1106 if (length != 4)
1107 {
1108 zlog (peer->log, LOG_ERR,
1109 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001110
Paul Jakma835315b2012-01-18 12:28:30 +00001111 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001112 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001113 args->total);
paul718e3742002-12-13 20:15:29 +00001114 }
1115
1116 attr->med = stream_getl (peer->ibuf);
1117
1118 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1119
Paul Jakmab881c702010-11-23 16:35:42 +00001120 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001121}
1122
1123/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001124static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001125bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001126{
Paul Jakma835315b2012-01-18 12:28:30 +00001127 struct peer *const peer = args->peer;
1128 struct attr *const attr = args->attr;
1129 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001130
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001131 /* Length check. */
1132 if (length != 4)
1133 {
Paul Jakma835315b2012-01-18 12:28:30 +00001134 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1135 length);
1136 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001137 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001138 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001139 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001140
paul718e3742002-12-13 20:15:29 +00001141 /* If it is contained in an UPDATE message that is received from an
1142 external peer, then this attribute MUST be ignored by the
1143 receiving speaker. */
1144 if (peer_sort (peer) == BGP_PEER_EBGP)
1145 {
paul9985f832005-02-09 15:51:56 +00001146 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001147 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001148 }
1149
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001150 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001151
1152 /* Set atomic aggregate flag. */
1153 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1154
Paul Jakmab881c702010-11-23 16:35:42 +00001155 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001156}
1157
1158/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001159static int
Paul Jakma835315b2012-01-18 12:28:30 +00001160bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001161{
Paul Jakma835315b2012-01-18 12:28:30 +00001162 struct peer *const peer = args->peer;
1163 struct attr *const attr = args->attr;
1164 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001165
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001166 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001167 if (length != 0)
1168 {
Paul Jakma835315b2012-01-18 12:28:30 +00001169 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1170 length);
1171 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001172 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001173 args->total);
paul718e3742002-12-13 20:15:29 +00001174 }
1175
1176 /* Set atomic aggregate flag. */
1177 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1178
Paul Jakmab881c702010-11-23 16:35:42 +00001179 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001180}
1181
1182/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001183static int
Paul Jakma835315b2012-01-18 12:28:30 +00001184bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001185{
Paul Jakma835315b2012-01-18 12:28:30 +00001186 struct peer *const peer = args->peer;
1187 struct attr *const attr = args->attr;
1188 const bgp_size_t length = args->length;
1189
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001190 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001191 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001192
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001193 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001194 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001195 wantedlen = 8;
1196
1197 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001198 {
Paul Jakma835315b2012-01-18 12:28:30 +00001199 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1200 wantedlen, length);
1201 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001202 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001203 args->total);
paul718e3742002-12-13 20:15:29 +00001204 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205
1206 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1207 attre->aggregator_as = stream_getl (peer->ibuf);
1208 else
1209 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001210 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001211
1212 /* Set atomic aggregate flag. */
1213 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1214
Paul Jakmab881c702010-11-23 16:35:42 +00001215 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001216}
1217
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001218/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001219static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001220bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1221 as_t *as4_aggregator_as,
1222 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001223{
Paul Jakma835315b2012-01-18 12:28:30 +00001224 struct peer *const peer = args->peer;
1225 struct attr *const attr = args->attr;
1226 const bgp_size_t length = args->length;
1227
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001228 if (length != 8)
1229 {
Paul Jakma835315b2012-01-18 12:28:30 +00001230 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1231 length);
1232 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001233 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001234 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001235 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001236
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001237 *as4_aggregator_as = stream_getl (peer->ibuf);
1238 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1239
1240 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1241
Paul Jakmab881c702010-11-23 16:35:42 +00001242 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001243}
1244
1245/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1246 */
Paul Jakmab881c702010-11-23 16:35:42 +00001247static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001248bgp_attr_munge_as4_attrs (struct peer *const peer,
1249 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001250 struct aspath *as4_path, as_t as4_aggregator,
1251 struct in_addr *as4_aggregator_addr)
1252{
1253 int ignore_as4_path = 0;
1254 struct aspath *newpath;
1255 struct attr_extra *attre = attr->extra;
1256
Paul Jakmab881c702010-11-23 16:35:42 +00001257 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001258 {
1259 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1260 * if given.
1261 * It is worth a warning though, because the peer really
1262 * should not send them
1263 */
1264 if (BGP_DEBUG(as4, AS4))
1265 {
1266 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1267 zlog_debug ("[AS4] %s %s AS4_PATH",
1268 peer->host, "AS4 capable peer, yet it sent");
1269
1270 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1271 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1272 peer->host, "AS4 capable peer, yet it sent");
1273 }
1274
Paul Jakmab881c702010-11-23 16:35:42 +00001275 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001276 }
1277
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001278 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1279 * because that may override AS4_PATH
1280 */
1281 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1282 {
Paul Jakmab881c702010-11-23 16:35:42 +00001283 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001284 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001285 assert (attre);
1286
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001287 /* received both.
1288 * if the as_number in aggregator is not AS_TRANS,
1289 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1290 * and the Aggregator shall be taken as
1291 * info on the aggregating node, and the AS_PATH
1292 * shall be taken as the AS_PATH
1293 * otherwise
1294 * the Aggregator shall be ignored and the
1295 * AS4_AGGREGATOR shall be taken as the
1296 * Aggregating node and the AS_PATH is to be
1297 * constructed "as in all other cases"
1298 */
Paul Jakmab881c702010-11-23 16:35:42 +00001299 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001300 {
1301 /* ignore */
1302 if ( BGP_DEBUG(as4, AS4))
1303 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1304 " send AGGREGATOR != AS_TRANS and"
1305 " AS4_AGGREGATOR, so ignore"
1306 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1307 ignore_as4_path = 1;
1308 }
1309 else
1310 {
1311 /* "New_aggregator shall be taken as aggregator" */
1312 attre->aggregator_as = as4_aggregator;
1313 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1314 }
1315 }
1316 else
1317 {
1318 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1319 * That is bogus - but reading the conditions
1320 * we have to handle AS4_AGGREGATOR as if it were
1321 * AGGREGATOR in that case
1322 */
1323 if ( BGP_DEBUG(as4, AS4))
1324 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1325 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1326 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001327 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001328 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1329 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1330 }
1331 }
1332
1333 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001334 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001335 {
1336 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001337 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001338 attr->aspath = aspath_intern (newpath);
1339 }
Paul Jakmab881c702010-11-23 16:35:42 +00001340 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001341}
1342
paul718e3742002-12-13 20:15:29 +00001343/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001344static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001345bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001346{
Paul Jakma835315b2012-01-18 12:28:30 +00001347 struct peer *const peer = args->peer;
1348 struct attr *const attr = args->attr;
1349 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001350
paul718e3742002-12-13 20:15:29 +00001351 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001352 {
1353 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001354 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001355 }
Paul Jakma0c466382010-12-05 17:17:26 +00001356
1357 attr->community =
1358 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1359
1360 /* XXX: fix community_parse to use stream API and remove this */
1361 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001362
Paul Jakma0c466382010-12-05 17:17:26 +00001363 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001364 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001365 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001366 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001367
paul718e3742002-12-13 20:15:29 +00001368 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1369
Paul Jakmab881c702010-11-23 16:35:42 +00001370 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001371}
1372
1373/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001374static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001375bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001376{
Paul Jakma835315b2012-01-18 12:28:30 +00001377 struct peer *const peer = args->peer;
1378 struct attr *const attr = args->attr;
1379 const bgp_size_t length = args->length;
1380
Denis Ovsienkod595b562011-09-30 15:08:54 +04001381 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001382 if (length != 4)
1383 {
1384 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1385
Paul Jakma835315b2012-01-18 12:28:30 +00001386 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001387 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001388 args->total);
paul718e3742002-12-13 20:15:29 +00001389 }
1390
Paul Jakmafb982c22007-05-04 20:15:47 +00001391 (bgp_attr_extra_get (attr))->originator_id.s_addr
1392 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001393
1394 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1395
Paul Jakmab881c702010-11-23 16:35:42 +00001396 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001397}
1398
1399/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001400static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001401bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001402{
Paul Jakma835315b2012-01-18 12:28:30 +00001403 struct peer *const peer = args->peer;
1404 struct attr *const attr = args->attr;
1405 const bgp_size_t length = args->length;
1406
paul718e3742002-12-13 20:15:29 +00001407 /* Check length. */
1408 if (length % 4)
1409 {
1410 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1411
Paul Jakma835315b2012-01-18 12:28:30 +00001412 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1413 args->total);
paul718e3742002-12-13 20:15:29 +00001414 }
1415
Paul Jakmafb982c22007-05-04 20:15:47 +00001416 (bgp_attr_extra_get (attr))->cluster
1417 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001418
1419 /* XXX: Fix cluster_parse to use stream API and then remove this */
1420 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001421
1422 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1423
Paul Jakmab881c702010-11-23 16:35:42 +00001424 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001425}
1426
1427/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001428int
Paul Jakma835315b2012-01-18 12:28:30 +00001429bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1430 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001431{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001432 afi_t afi;
1433 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001434 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001435 size_t start;
paul718e3742002-12-13 20:15:29 +00001436 int ret;
1437 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001438 struct peer *const peer = args->peer;
1439 struct attr *const attr = args->attr;
1440 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001441 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001442
paul718e3742002-12-13 20:15:29 +00001443 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001444 s = BGP_INPUT(peer);
1445 start = stream_get_getp(s);
1446
1447 /* safe to read statically sized header? */
1448#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001449#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001450 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001451 {
1452 zlog_info ("%s: %s sent invalid length, %lu",
1453 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001454 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001455 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001456
paul718e3742002-12-13 20:15:29 +00001457 /* Load AFI, SAFI. */
1458 afi = stream_getw (s);
1459 safi = stream_getc (s);
1460
1461 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001462 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001463
Paul Jakma03292802008-06-07 20:37:10 +00001464 if (LEN_LEFT < attre->mp_nexthop_len)
1465 {
1466 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1467 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001468 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001469 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001470
paul718e3742002-12-13 20:15:29 +00001471 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001472 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001473 {
1474 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001475 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001476 /* Probably needed for RFC 2283 */
1477 if (attr->nexthop.s_addr == 0)
1478 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001479 break;
1480 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001481 stream_getl (s); /* RD high */
1482 stream_getl (s); /* RD low */
1483 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001484 break;
1485#ifdef HAVE_IPV6
1486 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001487 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001488 break;
1489 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001490 stream_get (&attre->mp_nexthop_global, s, 16);
1491 stream_get (&attre->mp_nexthop_local, s, 16);
1492 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001493 {
1494 char buf1[INET6_ADDRSTRLEN];
1495 char buf2[INET6_ADDRSTRLEN];
1496
1497 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001498 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 +00001499 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001500 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001501 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001502 buf2, INET6_ADDRSTRLEN));
1503
Paul Jakmafb982c22007-05-04 20:15:47 +00001504 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001505 }
1506 break;
1507#endif /* HAVE_IPV6 */
1508 default:
Paul Jakma03292802008-06-07 20:37:10 +00001509 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1510 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001511 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001512 }
1513
Paul Jakma03292802008-06-07 20:37:10 +00001514 if (!LEN_LEFT)
1515 {
1516 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1517 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001518 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001519 }
paul718e3742002-12-13 20:15:29 +00001520
Paul Jakma6e4ab122007-04-10 19:36:48 +00001521 {
1522 u_char val;
1523 if ((val = stream_getc (s)))
1524 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1525 peer->host, val);
1526 }
1527
1528 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001529 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001530 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001531 {
1532 zlog_info ("%s: (%s) Failed to read NLRI",
1533 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001534 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001535 }
paul718e3742002-12-13 20:15:29 +00001536
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001537 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001538 {
1539 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001540 if (ret < 0)
1541 {
1542 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1543 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001544 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001545 }
paul718e3742002-12-13 20:15:29 +00001546 }
1547
1548 mp_update->afi = afi;
1549 mp_update->safi = safi;
1550 mp_update->nlri = stream_pnt (s);
1551 mp_update->length = nlri_len;
1552
paul9985f832005-02-09 15:51:56 +00001553 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001554
Paul Jakmab881c702010-11-23 16:35:42 +00001555 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001556#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001557}
1558
1559/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001560int
Paul Jakma835315b2012-01-18 12:28:30 +00001561bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001562 struct bgp_nlri *mp_withdraw)
1563{
1564 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001565 afi_t afi;
1566 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001567 u_int16_t withdraw_len;
1568 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001569 struct peer *const peer = args->peer;
1570 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001571
1572 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001573
1574#define BGP_MP_UNREACH_MIN_SIZE 3
1575 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001576 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001577
paul718e3742002-12-13 20:15:29 +00001578 afi = stream_getw (s);
1579 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001580
1581 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001582
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001583 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001584 {
1585 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1586 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001587 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001588 }
1589
1590 mp_withdraw->afi = afi;
1591 mp_withdraw->safi = safi;
1592 mp_withdraw->nlri = stream_pnt (s);
1593 mp_withdraw->length = withdraw_len;
1594
paul9985f832005-02-09 15:51:56 +00001595 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001596
Paul Jakmab881c702010-11-23 16:35:42 +00001597 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001598}
1599
1600/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001601static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001602bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001603{
Paul Jakma835315b2012-01-18 12:28:30 +00001604 struct peer *const peer = args->peer;
1605 struct attr *const attr = args->attr;
1606 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001607
paul718e3742002-12-13 20:15:29 +00001608 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001609 {
1610 if (attr->extra)
1611 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001612 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001613 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001614 }
Paul Jakma0c466382010-12-05 17:17:26 +00001615
1616 (bgp_attr_extra_get (attr))->ecommunity =
1617 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1618 /* XXX: fix ecommunity_parse to use stream API */
1619 stream_forward_getp (peer->ibuf, length);
1620
1621 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001622 return bgp_attr_malformed (args,
1623 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1624 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001625
paul718e3742002-12-13 20:15:29 +00001626 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1627
Paul Jakmab881c702010-11-23 16:35:42 +00001628 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001629}
1630
1631/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001632static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001633bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001634{
1635 bgp_size_t total;
1636 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001637 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001638 struct peer *const peer = args->peer;
1639 struct attr *const attr = args->attr;
1640 u_char *const startp = args->startp;
1641 const u_char type = args->type;
1642 const u_char flag = args->flags;
1643 const bgp_size_t length = args->length;
1644
paul718e3742002-12-13 20:15:29 +00001645
hassof4184462005-02-01 20:13:16 +00001646 if (BGP_DEBUG (normal, NORMAL))
1647 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1648 peer->host, type, length);
1649
paul718e3742002-12-13 20:15:29 +00001650 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001651 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001652 "Unknown attribute type %d length %d is received", type, length);
1653
1654 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001655 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001656
paul718e3742002-12-13 20:15:29 +00001657 /* If any of the mandatory well-known attributes are not recognized,
1658 then the Error Subcode is set to Unrecognized Well-known
1659 Attribute. The Data field contains the unrecognized attribute
1660 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001661 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001662 {
Paul Jakma835315b2012-01-18 12:28:30 +00001663 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001664 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001665 args->total);
paul718e3742002-12-13 20:15:29 +00001666 }
1667
1668 /* Unrecognized non-transitive optional attributes must be quietly
1669 ignored and not passed along to other BGP peers. */
1670 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001671 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001672
1673 /* If a path with recognized transitive optional attribute is
1674 accepted and passed along to other BGP peers and the Partial bit
1675 in the Attribute Flags octet is set to 1 by some previous AS, it
1676 is not set back to 0 by the current AS. */
1677 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1678
1679 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001680 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001681 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001682
Paul Jakmafb982c22007-05-04 20:15:47 +00001683 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001684
1685 if (transit->val)
1686 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1687 transit->length + total);
1688 else
1689 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1690
1691 memcpy (transit->val + transit->length, startp, total);
1692 transit->length += total;
1693
Paul Jakmab881c702010-11-23 16:35:42 +00001694 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001695}
1696
1697/* Read attribute of update packet. This function is called from
1698 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001699bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001700bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1701 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1702{
1703 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001704 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001705 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001706 bgp_size_t length;
1707 u_char *startp, *endp;
1708 u_char *attr_endp;
1709 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001710 /* we need the as4_path only until we have synthesized the as_path with it */
1711 /* same goes for as4_aggregator */
1712 struct aspath *as4_path = NULL;
1713 as_t as4_aggregator = 0;
1714 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001715
1716 /* Initialize bitmap. */
1717 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1718
1719 /* End pointer of BGP attribute. */
1720 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001721
paul718e3742002-12-13 20:15:29 +00001722 /* Get attributes to the end of attribute length. */
1723 while (BGP_INPUT_PNT (peer) < endp)
1724 {
1725 /* Check remaining length check.*/
1726 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1727 {
gdtc29fdba2004-12-09 14:46:46 +00001728 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001729 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001730 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001731 peer->host,
1732 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001733
1734 bgp_notify_send (peer,
1735 BGP_NOTIFY_UPDATE_ERR,
1736 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001737 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001738 }
1739
1740 /* Fetch attribute flag and type. */
1741 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001742 /* "The lower-order four bits of the Attribute Flags octet are
1743 unused. They MUST be zero when sent and MUST be ignored when
1744 received." */
1745 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001746 type = stream_getc (BGP_INPUT (peer));
1747
Paul Jakma370b64a2007-12-22 16:49:52 +00001748 /* Check whether Extended-Length applies and is in bounds */
1749 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1750 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1751 {
1752 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001753 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001754 peer->host,
1755 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1756
1757 bgp_notify_send (peer,
1758 BGP_NOTIFY_UPDATE_ERR,
1759 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001760 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001761 }
Paul Jakma835315b2012-01-18 12:28:30 +00001762
paul718e3742002-12-13 20:15:29 +00001763 /* Check extended attribue length bit. */
1764 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1765 length = stream_getw (BGP_INPUT (peer));
1766 else
1767 length = stream_getc (BGP_INPUT (peer));
1768
1769 /* If any attribute appears more than once in the UPDATE
1770 message, then the Error Subcode is set to Malformed Attribute
1771 List. */
1772
1773 if (CHECK_BITMAP (seen, type))
1774 {
1775 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001776 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001777 peer->host, type);
1778
1779 bgp_notify_send (peer,
1780 BGP_NOTIFY_UPDATE_ERR,
1781 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001782 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001783 }
1784
1785 /* Set type to bitmap to check duplicate attribute. `type' is
1786 unsigned char so it never overflow bitmap range. */
1787
1788 SET_BITMAP (seen, type);
1789
1790 /* Overflow check. */
1791 attr_endp = BGP_INPUT_PNT (peer) + length;
1792
1793 if (attr_endp > endp)
1794 {
1795 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001796 "%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 +00001797 bgp_notify_send (peer,
1798 BGP_NOTIFY_UPDATE_ERR,
1799 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001800 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001801 }
Paul Jakma835315b2012-01-18 12:28:30 +00001802
1803 struct bgp_attr_parser_args attr_args = {
1804 .peer = peer,
1805 .length = length,
1806 .attr = attr,
1807 .type = type,
1808 .flags = flag,
1809 .startp = startp,
1810 .total = attr_endp - startp,
1811 };
1812
1813
1814 /* If any recognized attribute has Attribute Flags that conflict
1815 with the Attribute Type Code, then the Error Subcode is set to
1816 Attribute Flags Error. The Data field contains the erroneous
1817 attribute (type, length and value). */
1818 if (bgp_attr_flag_invalid (&attr_args))
1819 return bgp_attr_malformed (&attr_args,
1820 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1821 attr_args.total);
paul718e3742002-12-13 20:15:29 +00001822
1823 /* OK check attribute and store it's value. */
1824 switch (type)
1825 {
1826 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001827 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001828 break;
1829 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001830 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001831 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001832 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001833 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001834 break;
paul718e3742002-12-13 20:15:29 +00001835 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001836 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001837 break;
1838 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001839 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001840 break;
1841 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001842 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001843 break;
1844 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001845 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001846 break;
1847 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001848 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001849 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001850 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001851 ret = bgp_attr_as4_aggregator (&attr_args,
1852 &as4_aggregator,
1853 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001854 break;
paul718e3742002-12-13 20:15:29 +00001855 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001856 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001857 break;
1858 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001859 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001860 break;
1861 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001862 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001863 break;
1864 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001865 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001866 break;
1867 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001868 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001869 break;
1870 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001871 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001872 break;
1873 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001874 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001875 break;
1876 }
Paul Jakmab881c702010-11-23 16:35:42 +00001877
1878 /* If hard error occured immediately return to the caller. */
1879 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001880 {
1881 zlog (peer->log, LOG_WARNING,
1882 "%s: Attribute %s, parse error",
1883 peer->host,
1884 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001885 bgp_notify_send (peer,
1886 BGP_NOTIFY_UPDATE_ERR,
1887 BGP_NOTIFY_UPDATE_MAL_ATTR);
1888 if (as4_path)
1889 aspath_unintern (&as4_path);
1890 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001891 }
Paul Jakmab881c702010-11-23 16:35:42 +00001892 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1893 {
1894
1895 zlog (peer->log, LOG_WARNING,
1896 "%s: Attribute %s, parse error - treating as withdrawal",
1897 peer->host,
1898 LOOKUP (attr_str, type));
1899 if (as4_path)
1900 aspath_unintern (&as4_path);
1901 return ret;
1902 }
1903
paul718e3742002-12-13 20:15:29 +00001904 /* Check the fetched length. */
1905 if (BGP_INPUT_PNT (peer) != attr_endp)
1906 {
1907 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001908 "%s: BGP attribute %s, fetch error",
1909 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001910 bgp_notify_send (peer,
1911 BGP_NOTIFY_UPDATE_ERR,
1912 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001913 if (as4_path)
1914 aspath_unintern (&as4_path);
1915 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001916 }
1917 }
1918
1919 /* Check final read pointer is same as end pointer. */
1920 if (BGP_INPUT_PNT (peer) != endp)
1921 {
1922 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001923 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001924 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001925 bgp_notify_send (peer,
1926 BGP_NOTIFY_UPDATE_ERR,
1927 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001928 if (as4_path)
1929 aspath_unintern (&as4_path);
1930 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001931 }
1932
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001933 /*
1934 * At this place we can see whether we got AS4_PATH and/or
1935 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1936 * We can not do this before we've read all attributes because
1937 * the as4 handling does not say whether AS4_PATH has to be sent
1938 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1939 * in relationship to AGGREGATOR.
1940 * So, to be defensive, we are not relying on any order and read
1941 * all attributes first, including these 32bit ones, and now,
1942 * afterwards, we look what and if something is to be done for as4.
1943 */
Paul Jakma835315b2012-01-18 12:28:30 +00001944 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001945 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001946 {
1947 if (as4_path)
1948 aspath_unintern (&as4_path);
1949 return BGP_ATTR_PARSE_ERROR;
1950 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001951
1952 /* At this stage, we have done all fiddling with as4, and the
1953 * resulting info is in attr->aggregator resp. attr->aspath
1954 * so we can chuck as4_aggregator and as4_path alltogether in
1955 * order to save memory
1956 */
Paul Jakmab881c702010-11-23 16:35:42 +00001957 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001958 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001959 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001960 /* The flag that we got this is still there, but that does not
1961 * do any trouble
1962 */
1963 }
1964 /*
1965 * The "rest" of the code does nothing with as4_aggregator.
1966 * there is no memory attached specifically which is not part
1967 * of the attr.
1968 * so ignoring just means do nothing.
1969 */
1970 /*
1971 * Finally do the checks on the aspath we did not do yet
1972 * because we waited for a potentially synthesized aspath.
1973 */
Paul Jakmab881c702010-11-23 16:35:42 +00001974 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001975 {
Paul Jakma835315b2012-01-18 12:28:30 +00001976 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001977 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001978 return ret;
1979 }
1980
paul718e3742002-12-13 20:15:29 +00001981 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001982 if (attr->extra && attr->extra->transit)
1983 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001984
Paul Jakmab881c702010-11-23 16:35:42 +00001985 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001986}
1987
1988/* Well-known attribute check. */
1989int
1990bgp_attr_check (struct peer *peer, struct attr *attr)
1991{
1992 u_char type = 0;
1993
1994 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1995 type = BGP_ATTR_ORIGIN;
1996
1997 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1998 type = BGP_ATTR_AS_PATH;
1999
2000 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2001 type = BGP_ATTR_NEXT_HOP;
2002
2003 if (peer_sort (peer) == BGP_PEER_IBGP
2004 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2005 type = BGP_ATTR_LOCAL_PREF;
2006
2007 if (type)
2008 {
2009 zlog (peer->log, LOG_WARNING,
2010 "%s Missing well-known attribute %d.",
2011 peer->host, type);
2012 bgp_notify_send_with_data (peer,
2013 BGP_NOTIFY_UPDATE_ERR,
2014 BGP_NOTIFY_UPDATE_MISS_ATTR,
2015 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002016 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002017 }
Paul Jakmab881c702010-11-23 16:35:42 +00002018 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002019}
2020
2021int stream_put_prefix (struct stream *, struct prefix *);
2022
2023/* Make attribute packet. */
2024bgp_size_t
2025bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2026 struct stream *s, struct attr *attr, struct prefix *p,
2027 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002028 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002029{
paulfe69a502005-09-10 16:55:02 +00002030 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002031 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002032 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002033 int send_as4_path = 0;
2034 int send_as4_aggregator = 0;
2035 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002036
2037 if (! bgp)
2038 bgp = bgp_get_default ();
2039
2040 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002041 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002042
2043 /* Origin attribute. */
2044 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2045 stream_putc (s, BGP_ATTR_ORIGIN);
2046 stream_putc (s, 1);
2047 stream_putc (s, attr->origin);
2048
2049 /* AS path attribute. */
2050
2051 /* If remote-peer is EBGP */
2052 if (peer_sort (peer) == BGP_PEER_EBGP
2053 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002054 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002055 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002056 {
2057 aspath = aspath_dup (attr->aspath);
2058
2059 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2060 {
2061 /* Strip the confed info, and then stuff our path CONFED_ID
2062 on the front */
2063 aspath = aspath_delete_confed_seq (aspath);
2064 aspath = aspath_add_seq (aspath, bgp->confed_id);
2065 }
2066 else
2067 {
2068 aspath = aspath_add_seq (aspath, peer->local_as);
2069 if (peer->change_local_as)
2070 aspath = aspath_add_seq (aspath, peer->change_local_as);
2071 }
2072 }
2073 else if (peer_sort (peer) == BGP_PEER_CONFED)
2074 {
2075 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2076 aspath = aspath_dup (attr->aspath);
2077 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2078 }
2079 else
2080 aspath = attr->aspath;
2081
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002082 /* If peer is not AS4 capable, then:
2083 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2084 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2085 * types are in it (i.e. exclude them if they are there)
2086 * AND do this only if there is at least one asnum > 65535 in the path!
2087 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2088 * all ASnums > 65535 to BGP_AS_TRANS
2089 */
paul718e3742002-12-13 20:15:29 +00002090
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002091 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2092 stream_putc (s, BGP_ATTR_AS_PATH);
2093 aspath_sizep = stream_get_endp (s);
2094 stream_putw (s, 0);
2095 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2096
2097 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2098 * in the path
2099 */
2100 if (!use32bit && aspath_has_as4 (aspath))
2101 send_as4_path = 1; /* we'll do this later, at the correct place */
2102
paul718e3742002-12-13 20:15:29 +00002103 /* Nexthop attribute. */
2104 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2105 {
2106 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2107 stream_putc (s, BGP_ATTR_NEXT_HOP);
2108 stream_putc (s, 4);
2109 if (safi == SAFI_MPLS_VPN)
2110 {
2111 if (attr->nexthop.s_addr == 0)
2112 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2113 else
2114 stream_put_ipv4 (s, attr->nexthop.s_addr);
2115 }
2116 else
2117 stream_put_ipv4 (s, attr->nexthop.s_addr);
2118 }
2119
2120 /* MED attribute. */
2121 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2122 {
2123 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2124 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2125 stream_putc (s, 4);
2126 stream_putl (s, attr->med);
2127 }
2128
2129 /* Local preference. */
2130 if (peer_sort (peer) == BGP_PEER_IBGP ||
2131 peer_sort (peer) == BGP_PEER_CONFED)
2132 {
2133 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2134 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2135 stream_putc (s, 4);
2136 stream_putl (s, attr->local_pref);
2137 }
2138
2139 /* Atomic aggregate. */
2140 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2141 {
2142 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2143 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2144 stream_putc (s, 0);
2145 }
2146
2147 /* Aggregator. */
2148 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2149 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002150 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002151
2152 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002153 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2154 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002155
2156 if (use32bit)
2157 {
2158 /* AS4 capable peer */
2159 stream_putc (s, 8);
2160 stream_putl (s, attr->extra->aggregator_as);
2161 }
2162 else
2163 {
2164 /* 2-byte AS peer */
2165 stream_putc (s, 6);
2166
2167 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2168 if ( attr->extra->aggregator_as > 65535 )
2169 {
2170 stream_putw (s, BGP_AS_TRANS);
2171
2172 /* we have to send AS4_AGGREGATOR, too.
2173 * we'll do that later in order to send attributes in ascending
2174 * order.
2175 */
2176 send_as4_aggregator = 1;
2177 }
2178 else
2179 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2180 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002181 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002182 }
2183
2184 /* Community attribute. */
2185 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2186 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2187 {
2188 if (attr->community->size * 4 > 255)
2189 {
2190 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2191 stream_putc (s, BGP_ATTR_COMMUNITIES);
2192 stream_putw (s, attr->community->size * 4);
2193 }
2194 else
2195 {
2196 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2197 stream_putc (s, BGP_ATTR_COMMUNITIES);
2198 stream_putc (s, attr->community->size * 4);
2199 }
2200 stream_put (s, attr->community->val, attr->community->size * 4);
2201 }
2202
2203 /* Route Reflector. */
2204 if (peer_sort (peer) == BGP_PEER_IBGP
2205 && from
2206 && peer_sort (from) == BGP_PEER_IBGP)
2207 {
2208 /* Originator ID. */
2209 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2210 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2211 stream_putc (s, 4);
2212
2213 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002214 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002215 else
2216 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002217
2218 /* Cluster list. */
2219 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2220 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2221
Paul Jakma9eda90c2007-08-30 13:36:17 +00002222 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002223 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002224 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002225 /* If this peer configuration's parent BGP has cluster_id. */
2226 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2227 stream_put_in_addr (s, &bgp->cluster_id);
2228 else
2229 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002230 stream_put (s, attr->extra->cluster->list,
2231 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002232 }
2233 else
2234 {
2235 stream_putc (s, 4);
2236 /* If this peer configuration's parent BGP has cluster_id. */
2237 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2238 stream_put_in_addr (s, &bgp->cluster_id);
2239 else
2240 stream_put_in_addr (s, &bgp->router_id);
2241 }
2242 }
2243
2244#ifdef HAVE_IPV6
2245 /* If p is IPv6 address put it into attribute. */
2246 if (p->family == AF_INET6)
2247 {
2248 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002249 struct attr_extra *attre = attr->extra;
2250
2251 assert (attr->extra);
2252
paul718e3742002-12-13 20:15:29 +00002253 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2254 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002255 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002256 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002257 stream_putw (s, AFI_IP6); /* AFI */
2258 stream_putc (s, safi); /* SAFI */
2259
Paul Jakmafb982c22007-05-04 20:15:47 +00002260 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002261
Paul Jakmafb982c22007-05-04 20:15:47 +00002262 if (attre->mp_nexthop_len == 16)
2263 stream_put (s, &attre->mp_nexthop_global, 16);
2264 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002265 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002266 stream_put (s, &attre->mp_nexthop_global, 16);
2267 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002268 }
2269
2270 /* SNPA */
2271 stream_putc (s, 0);
2272
paul718e3742002-12-13 20:15:29 +00002273 /* Prefix write. */
2274 stream_put_prefix (s, p);
2275
2276 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002277 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002278 }
2279#endif /* HAVE_IPV6 */
2280
2281 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2282 {
2283 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002284
2285 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2286 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002287 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002288 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002289 stream_putw (s, AFI_IP); /* AFI */
2290 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2291
2292 stream_putc (s, 4);
2293 stream_put_ipv4 (s, attr->nexthop.s_addr);
2294
2295 /* SNPA */
2296 stream_putc (s, 0);
2297
paul718e3742002-12-13 20:15:29 +00002298 /* Prefix write. */
2299 stream_put_prefix (s, p);
2300
2301 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002302 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002303 }
2304
2305 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2306 {
2307 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002308
2309 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2310 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002311 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002312 stream_putc (s, 0); /* Length of this attribute. */
2313 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002314 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002315
2316 stream_putc (s, 12);
2317 stream_putl (s, 0);
2318 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002319 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002320
2321 /* SNPA */
2322 stream_putc (s, 0);
2323
paul718e3742002-12-13 20:15:29 +00002324 /* Tag, RD, Prefix write. */
2325 stream_putc (s, p->prefixlen + 88);
2326 stream_put (s, tag, 3);
2327 stream_put (s, prd->val, 8);
2328 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2329
2330 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002331 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002332 }
2333
2334 /* Extended Communities attribute. */
2335 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2336 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2337 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002338 struct attr_extra *attre = attr->extra;
2339
2340 assert (attre);
2341
2342 if (peer_sort (peer) == BGP_PEER_IBGP
2343 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002344 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002345 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002346 {
2347 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2348 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002349 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002350 }
2351 else
2352 {
2353 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2354 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002355 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002356 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002357 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002358 }
2359 else
2360 {
paul5228ad22004-06-04 17:58:18 +00002361 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002362 int tbit;
2363 int ecom_tr_size = 0;
2364 int i;
2365
Paul Jakmafb982c22007-05-04 20:15:47 +00002366 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002367 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002368 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002369 tbit = *pnt;
2370
2371 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2372 continue;
2373
2374 ecom_tr_size++;
2375 }
2376
2377 if (ecom_tr_size)
2378 {
2379 if (ecom_tr_size * 8 > 255)
2380 {
2381 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2382 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2383 stream_putw (s, ecom_tr_size * 8);
2384 }
2385 else
2386 {
2387 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2388 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2389 stream_putc (s, ecom_tr_size * 8);
2390 }
2391
Paul Jakmafb982c22007-05-04 20:15:47 +00002392 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002393 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002394 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002395 tbit = *pnt;
2396
2397 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2398 continue;
2399
2400 stream_put (s, pnt, 8);
2401 }
2402 }
paul718e3742002-12-13 20:15:29 +00002403 }
paul718e3742002-12-13 20:15:29 +00002404 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002405
2406 if ( send_as4_path )
2407 {
2408 /* If the peer is NOT As4 capable, AND */
2409 /* there are ASnums > 65535 in path THEN
2410 * give out AS4_PATH */
2411
2412 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2413 * path segments!
2414 * Hm, I wonder... confederation things *should* only be at
2415 * the beginning of an aspath, right? Then we should use
2416 * aspath_delete_confed_seq for this, because it is already
2417 * there! (JK)
2418 * Folks, talk to me: what is reasonable here!?
2419 */
2420 aspath = aspath_delete_confed_seq (aspath);
2421
2422 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2423 stream_putc (s, BGP_ATTR_AS4_PATH);
2424 aspath_sizep = stream_get_endp (s);
2425 stream_putw (s, 0);
2426 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2427 }
2428
2429 if (aspath != attr->aspath)
2430 aspath_free (aspath);
2431
2432 if ( send_as4_aggregator )
2433 {
2434 assert (attr->extra);
2435
2436 /* send AS4_AGGREGATOR, at this place */
2437 /* this section of code moved here in order to ensure the correct
2438 * *ascending* order of attributes
2439 */
2440 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2441 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2442 stream_putc (s, 8);
2443 stream_putl (s, attr->extra->aggregator_as);
2444 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2445 }
Paul Jakma41367172007-08-06 15:24:51 +00002446
paul718e3742002-12-13 20:15:29 +00002447 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002448 if (attr->extra && attr->extra->transit)
2449 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002450
2451 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002452 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002453}
2454
2455bgp_size_t
2456bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2457 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002458 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002459{
2460 unsigned long cp;
2461 unsigned long attrlen_pnt;
2462 bgp_size_t size;
2463
paul9985f832005-02-09 15:51:56 +00002464 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002465
2466 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2467 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2468
paul9985f832005-02-09 15:51:56 +00002469 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002470 stream_putc (s, 0); /* Length of this attribute. */
2471
2472 stream_putw (s, family2afi (p->family));
2473
2474 if (safi == SAFI_MPLS_VPN)
2475 {
2476 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002477 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002478
2479 /* prefix. */
2480 stream_putc (s, p->prefixlen + 88);
2481 stream_put (s, tag, 3);
2482 stream_put (s, prd->val, 8);
2483 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2484 }
2485 else
2486 {
2487 /* SAFI */
2488 stream_putc (s, safi);
2489
2490 /* prefix */
2491 stream_put_prefix (s, p);
2492 }
2493
2494 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002495 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002496 stream_putc_at (s, attrlen_pnt, size);
2497
paul9985f832005-02-09 15:51:56 +00002498 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002499}
2500
2501/* Initialization of attribute. */
2502void
paulfe69a502005-09-10 16:55:02 +00002503bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002504{
paul718e3742002-12-13 20:15:29 +00002505 aspath_init ();
2506 attrhash_init ();
2507 community_init ();
2508 ecommunity_init ();
2509 cluster_init ();
2510 transit_init ();
2511}
2512
Chris Caputo228da422009-07-18 05:44:03 +00002513void
2514bgp_attr_finish (void)
2515{
2516 aspath_finish ();
2517 attrhash_finish ();
2518 community_finish ();
2519 ecommunity_finish ();
2520 cluster_finish ();
2521 transit_finish ();
2522}
2523
paul718e3742002-12-13 20:15:29 +00002524/* Make attribute packet. */
2525void
paula3845922003-10-18 01:30:50 +00002526bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2527 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002528{
2529 unsigned long cp;
2530 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002531 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002532 struct aspath *aspath;
2533
2534 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002535 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002536
2537 /* Place holder of length. */
2538 stream_putw (s, 0);
2539
2540 /* Origin attribute. */
2541 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2542 stream_putc (s, BGP_ATTR_ORIGIN);
2543 stream_putc (s, 1);
2544 stream_putc (s, attr->origin);
2545
2546 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002547
2548 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2549 stream_putc (s, BGP_ATTR_AS_PATH);
2550 aspath_lenp = stream_get_endp (s);
2551 stream_putw (s, 0);
2552
2553 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002554
2555 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002556 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2557 if(prefix != NULL
2558#ifdef HAVE_IPV6
2559 && prefix->family != AF_INET6
2560#endif /* HAVE_IPV6 */
2561 )
2562 {
2563 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2564 stream_putc (s, BGP_ATTR_NEXT_HOP);
2565 stream_putc (s, 4);
2566 stream_put_ipv4 (s, attr->nexthop.s_addr);
2567 }
paul718e3742002-12-13 20:15:29 +00002568
2569 /* MED attribute. */
2570 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2571 {
2572 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2573 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2574 stream_putc (s, 4);
2575 stream_putl (s, attr->med);
2576 }
2577
2578 /* Local preference. */
2579 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2580 {
2581 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2582 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2583 stream_putc (s, 4);
2584 stream_putl (s, attr->local_pref);
2585 }
2586
2587 /* Atomic aggregate. */
2588 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2589 {
2590 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2591 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2592 stream_putc (s, 0);
2593 }
2594
2595 /* Aggregator. */
2596 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2597 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002598 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002599 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2600 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002601 stream_putc (s, 8);
2602 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002603 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002604 }
2605
2606 /* Community attribute. */
2607 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2608 {
2609 if (attr->community->size * 4 > 255)
2610 {
2611 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2612 stream_putc (s, BGP_ATTR_COMMUNITIES);
2613 stream_putw (s, attr->community->size * 4);
2614 }
2615 else
2616 {
2617 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2618 stream_putc (s, BGP_ATTR_COMMUNITIES);
2619 stream_putc (s, attr->community->size * 4);
2620 }
2621 stream_put (s, attr->community->val, attr->community->size * 4);
2622 }
2623
paula3845922003-10-18 01:30:50 +00002624#ifdef HAVE_IPV6
2625 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002626 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2627 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002628 {
2629 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002630 struct attr_extra *attre = attr->extra;
2631
paula3845922003-10-18 01:30:50 +00002632 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2633 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002634 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002635
2636 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002637 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002638 stream_putw(s, AFI_IP6); /* AFI */
2639 stream_putc(s, SAFI_UNICAST); /* SAFI */
2640
2641 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002642 stream_putc(s, attre->mp_nexthop_len);
2643 stream_put(s, &attre->mp_nexthop_global, 16);
2644 if (attre->mp_nexthop_len == 32)
2645 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002646
2647 /* SNPA */
2648 stream_putc(s, 0);
2649
2650 /* Prefix */
2651 stream_put_prefix(s, prefix);
2652
2653 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002654 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002655 }
2656#endif /* HAVE_IPV6 */
2657
paul718e3742002-12-13 20:15:29 +00002658 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002659 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002660 stream_putw_at (s, cp, len);
2661}