blob: d8ca831a90b85dc22d3826cb9a89034ed2dd3a67 [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
713bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
714 u_char subcode, u_char *startp, bgp_size_t length)
715{
716 /* Only relax error handling for eBGP peers */
717 if (peer_sort (peer) != BGP_PEER_EBGP)
718 {
719 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
720 startp, length);
721 return BGP_ATTR_PARSE_ERROR;
722
723 }
724
725 switch (type) {
726 /* where an optional attribute is inconsequential, e.g. it does not affect
727 * route selection, and can be safely ignored then any such attributes
728 * which are malformed should just be ignored and the route processed as
729 * normal.
730 */
731 case BGP_ATTR_AS4_AGGREGATOR:
732 case BGP_ATTR_AGGREGATOR:
733 case BGP_ATTR_ATOMIC_AGGREGATE:
734 return BGP_ATTR_PARSE_PROCEED;
735
736 /* Core attributes, particularly ones which may influence route
737 * selection should always cause session resets
738 */
739 case BGP_ATTR_ORIGIN:
740 case BGP_ATTR_AS_PATH:
741 case BGP_ATTR_NEXT_HOP:
742 case BGP_ATTR_MULTI_EXIT_DISC:
743 case BGP_ATTR_LOCAL_PREF:
744 case BGP_ATTR_COMMUNITIES:
745 case BGP_ATTR_ORIGINATOR_ID:
746 case BGP_ATTR_CLUSTER_LIST:
747 case BGP_ATTR_MP_REACH_NLRI:
748 case BGP_ATTR_MP_UNREACH_NLRI:
749 case BGP_ATTR_EXT_COMMUNITIES:
750 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
751 startp, length);
752 return BGP_ATTR_PARSE_ERROR;
753 }
754
755 /* Partial optional attributes that are malformed should not cause
756 * the whole session to be reset. Instead treat it as a withdrawal
757 * of the routes, if possible.
758 */
759 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
760 && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
761 && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
762 return BGP_ATTR_PARSE_WITHDRAW;
763
764 /* default to reset */
765 return BGP_ATTR_PARSE_ERROR;
766}
767
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400768/* Find out what is wrong with the path attribute flag bits and log the error.
769 "Flag bits" here stand for Optional, Transitive and Partial, but not for
770 Extended Length. Checking O/T/P bits at once implies, that the attribute
771 being diagnosed is defined by RFC as either a "well-known" or an "optional,
772 non-transitive" attribute. */
773static void
774bgp_attr_flags_diagnose
775(
776 struct peer * peer,
777 const u_int8_t attr_code,
778 u_int8_t desired_flags, /* how RFC says it must be */
779 u_int8_t real_flags /* on wire */
780)
781{
782 u_char seen = 0, i;
783
784 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
785 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
786 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
787 if
788 (
789 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
790 CHECK_FLAG (real_flags, attr_flag_str[i].key)
791 )
792 {
793 zlog (peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
794 LOOKUP (attr_str, attr_code),
795 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
796 attr_flag_str[i].str);
797 seen = 1;
798 }
799 assert (seen);
800}
801
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000802/* Required flags for attributes. EXTLEN will be masked off when testing,
803 * as will PARTIAL for optional+transitive attributes.
804 */
805const u_int8_t attr_flags_values [] = {
806 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
807 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
808 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
809 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
810 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
811 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
812 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
813 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
814 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
815 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
816 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
817 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
818 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
819 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
820 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
821};
822static const size_t attr_flags_values_max =
823 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
824
825static int
826bgp_attr_flag_invalid (struct peer *peer, u_int8_t attr_code, u_int8_t flags)
827{
828 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
829
830 /* there may be attributes we don't know about */
831 if (attr_code > attr_flags_values_max)
832 return 0;
833 if (attr_flags_values[attr_code] == 0)
834 return 0;
835
836 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
837 * 1."
838 */
839 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
840 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
841 {
842 zlog (peer->log, LOG_ERR,
843 "%s well-known attributes must have transitive flag set (%x)",
844 LOOKUP (attr_str, attr_code), flags);
845 return 1;
846 }
847
848 /* "For well-known attributes and for optional non-transitive attributes,
849 * the Partial bit MUST be set to 0."
850 */
851 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
852 {
853 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
854 {
855 zlog (peer->log, LOG_ERR,
856 "%s well-known attribute "
857 "must NOT have the partial flag set (%x)",
858 LOOKUP (attr_str, attr_code), flags);
859 return 1;
860 }
861 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
862 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
863 {
864 zlog (peer->log, LOG_ERR,
865 "%s optional + transitive attribute "
866 "must NOT have the partial flag set (%x)",
867 LOOKUP (attr_str, attr_code), flags);
868 return 1;
869 }
870 }
871
872 /* Optional transitive attributes may go through speakers that don't
873 * reocgnise them and set the Partial bit.
874 */
875 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
876 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
877 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
878
879 if ((flags & ~attr_flags_values[attr_code])
880 == attr_flags_values[attr_code])
881 return 0;
882
883 bgp_attr_flags_diagnose (peer, attr_code, attr_flags_values[attr_code],
884 flags);
885 return 1;
886}
887
paul718e3742002-12-13 20:15:29 +0000888/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000889static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000890bgp_attr_origin (struct peer *peer, bgp_size_t length,
891 struct attr *attr, u_char flag, u_char *startp)
892{
893 bgp_size_t total;
894
895 /* total is entire attribute length include Attribute Flags (1),
896 Attribute Type code (1) and Attribute length (1 or 2). */
897 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
898
899 /* If any recognized attribute has Attribute Flags that conflict
900 with the Attribute Type Code, then the Error Subcode is set to
901 Attribute Flags Error. The Data field contains the erroneous
902 attribute (type, length and value). */
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000903 if (bgp_attr_flag_invalid (peer, BGP_ATTR_ORIGIN, flag))
904 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
905 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
906 startp, total);
paul718e3742002-12-13 20:15:29 +0000907
908 /* If any recognized attribute has Attribute Length that conflicts
909 with the expected length (based on the attribute type code), then
910 the Error Subcode is set to Attribute Length Error. The Data
911 field contains the erroneous attribute (type, length and
912 value). */
913 if (length != 1)
914 {
915 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
916 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000917 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
918 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
919 startp, total);
paul718e3742002-12-13 20:15:29 +0000920 }
921
922 /* Fetch origin attribute. */
923 attr->origin = stream_getc (BGP_INPUT (peer));
924
925 /* If the ORIGIN attribute has an undefined value, then the Error
926 Subcode is set to Invalid Origin Attribute. The Data field
927 contains the unrecognized attribute (type, length and value). */
928 if ((attr->origin != BGP_ORIGIN_IGP)
929 && (attr->origin != BGP_ORIGIN_EGP)
930 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
931 {
932 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
933 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000934 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
935 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
936 startp, total);
paul718e3742002-12-13 20:15:29 +0000937 }
938
939 /* Set oring attribute flag. */
940 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
941
942 return 0;
943}
Paul Jakmaab005292010-11-27 22:48:34 +0000944
945/* Parse AS path information. This function is wrapper of
946 aspath_parse. */
947static int
paul718e3742002-12-13 20:15:29 +0000948bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000949 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000950{
Paul Jakmaab005292010-11-27 22:48:34 +0000951 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000952
Paul Jakmaab005292010-11-27 22:48:34 +0000953 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Paul Jakma83a9a222012-01-08 14:15:03 +0000954
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000955 if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS_PATH, flag))
Paul Jakmab881c702010-11-23 16:35:42 +0000956 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000957 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
958 startp, total);
Paul Jakmaab005292010-11-27 22:48:34 +0000959 /*
960 * peer with AS4 => will get 4Byte ASnums
961 * otherwise, will get 16 Bit
962 */
963 attr->aspath = aspath_parse (peer->ibuf, length,
964 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
965
966 /* In case of IBGP, length will be zero. */
967 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000968 {
Paul Jakmab881c702010-11-23 16:35:42 +0000969 zlog (peer->log, LOG_ERR,
970 "Malformed AS path from %s, length is %d",
971 peer->host, length);
972 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
973 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
974 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000975 }
Chris Hallcddb8112010-08-09 22:31:37 +0400976
Paul Jakmaab005292010-11-27 22:48:34 +0000977 /* Set aspath attribute flag. */
978 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000979
Paul Jakmab881c702010-11-23 16:35:42 +0000980 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000981}
982
Paul Jakmab881c702010-11-23 16:35:42 +0000983static bgp_attr_parse_ret_t
984bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000985{
986 /* These checks were part of bgp_attr_aspath, but with
987 * as4 we should to check aspath things when
988 * aspath synthesizing with as4_path has already taken place.
989 * Otherwise we check ASPATH and use the synthesized thing, and that is
990 * not right.
991 * So do the checks later, i.e. here
992 */
993 struct bgp *bgp = peer->bgp;
994 struct aspath *aspath;
995
paul718e3742002-12-13 20:15:29 +0000996 bgp = peer->bgp;
997
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300998 /* Confederation sanity check. */
999 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1000 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
1001 {
1002 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001003 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1004 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1005 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001006 }
1007
paul718e3742002-12-13 20:15:29 +00001008 /* First AS check for EBGP. */
1009 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1010 {
1011 if (peer_sort (peer) == BGP_PEER_EBGP
1012 && ! aspath_firstas_check (attr->aspath, peer->as))
1013 {
1014 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001015 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +00001016 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1017 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1018 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001019 }
1020 }
1021
1022 /* local-as prepend */
1023 if (peer->change_local_as &&
1024 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1025 {
1026 aspath = aspath_dup (attr->aspath);
1027 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001028 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001029 attr->aspath = aspath_intern (aspath);
1030 }
1031
Paul Jakmab881c702010-11-23 16:35:42 +00001032 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001033}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001034
Paul Jakmaab005292010-11-27 22:48:34 +00001035/* Parse AS4 path information. This function is another wrapper of
1036 aspath_parse. */
1037static int
Paul Jakmab881c702010-11-23 16:35:42 +00001038bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
1039 struct attr *attr, u_char flag, u_char *startp,
1040 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001041{
Paul Jakmab881c702010-11-23 16:35:42 +00001042 bgp_size_t total;
1043
1044 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1045
1046 /* Flag check. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001047 if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS4_PATH, flag))
Paul Jakmaf31d6922012-01-08 14:17:42 +00001048 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
Paul Jakmab881c702010-11-23 16:35:42 +00001049 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1050 startp, total);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001051
Paul Jakmaab005292010-11-27 22:48:34 +00001052 *as4_path = aspath_parse (peer->ibuf, length, 1);
1053
Paul Jakmab881c702010-11-23 16:35:42 +00001054 /* In case of IBGP, length will be zero. */
1055 if (!*as4_path)
1056 {
1057 zlog (peer->log, LOG_ERR,
1058 "Malformed AS4 path from %s, length is %d",
1059 peer->host, length);
1060 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
1061 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1062 NULL, 0);
1063 }
1064
Paul Jakmaab005292010-11-27 22:48:34 +00001065 /* Set aspath attribute flag. */
1066 if (as4_path)
1067 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1068
Paul Jakmab881c702010-11-23 16:35:42 +00001069 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001070}
1071
paul718e3742002-12-13 20:15:29 +00001072/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001073static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001074bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
1075 struct attr *attr, u_char flag, u_char *startp)
1076{
1077 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001078 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001079
1080 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1081
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001082 /* Flags check. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001083 if (bgp_attr_flag_invalid (peer, BGP_ATTR_NEXT_HOP, flag))
1084 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1085 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1086 startp, total);
paul718e3742002-12-13 20:15:29 +00001087
1088 /* Check nexthop attribute length. */
1089 if (length != 4)
1090 {
1091 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1092 length);
1093
Paul Jakmab881c702010-11-23 16:35:42 +00001094 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1095 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1096 startp, total);
paul718e3742002-12-13 20:15:29 +00001097 }
1098
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001099 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1100 attribute must result in a NOTIFICATION message (this is implemented below).
1101 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1102 logged locally (this is implemented somewhere else). The UPDATE message
1103 gets ignored in any of these cases. */
1104 nexthop_n = stream_get_ipv4 (peer->ibuf);
1105 nexthop_h = ntohl (nexthop_n);
1106 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1107 {
1108 char buf[INET_ADDRSTRLEN];
1109 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1110 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1111 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1112 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1113 startp, total);
1114 }
1115
1116 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001117 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1118
Paul Jakmab881c702010-11-23 16:35:42 +00001119 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001120}
1121
1122/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001123static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001124bgp_attr_med (struct peer *peer, bgp_size_t length,
1125 struct attr *attr, u_char flag, u_char *startp)
1126{
1127 bgp_size_t total;
1128
1129 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1130
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001131 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001132 if (bgp_attr_flag_invalid (peer, BGP_ATTR_MULTI_EXIT_DISC, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001133 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1134 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1135 startp, total);
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001136
paul718e3742002-12-13 20:15:29 +00001137 /* Length check. */
1138 if (length != 4)
1139 {
1140 zlog (peer->log, LOG_ERR,
1141 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001142
1143 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1144 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1145 startp, total);
paul718e3742002-12-13 20:15:29 +00001146 }
1147
1148 attr->med = stream_getl (peer->ibuf);
1149
1150 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1151
Paul Jakmab881c702010-11-23 16:35:42 +00001152 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001153}
1154
1155/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001156static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001157bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001158 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001159{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001160 bgp_size_t total;
1161
1162 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1163 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001164 if (bgp_attr_flag_invalid (peer, BGP_ATTR_LOCAL_PREF, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001165 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
1166 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1167 startp, total);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001168
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001169 /* Length check. */
1170 if (length != 4)
1171 {
1172 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001173 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001174 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1175 startp, total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001176 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001177
paul718e3742002-12-13 20:15:29 +00001178 /* If it is contained in an UPDATE message that is received from an
1179 external peer, then this attribute MUST be ignored by the
1180 receiving speaker. */
1181 if (peer_sort (peer) == BGP_PEER_EBGP)
1182 {
paul9985f832005-02-09 15:51:56 +00001183 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001184 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001185 }
1186
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001187 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001188
1189 /* Set atomic aggregate flag. */
1190 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1191
Paul Jakmab881c702010-11-23 16:35:42 +00001192 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001193}
1194
1195/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001196static int
paul718e3742002-12-13 20:15:29 +00001197bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001198 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001199{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001200 bgp_size_t total;
1201
1202 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1203 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001204 if (bgp_attr_flag_invalid (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001205 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1206 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1207 startp, total);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001208
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001209 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001210 if (length != 0)
1211 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001212 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001213 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1214 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001215 startp, total);
paul718e3742002-12-13 20:15:29 +00001216 }
1217
1218 /* Set atomic aggregate flag. */
1219 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1220
Paul Jakmab881c702010-11-23 16:35:42 +00001221 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001222}
1223
1224/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001225static int
paul718e3742002-12-13 20:15:29 +00001226bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001227 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001228{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001229 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001230 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001231 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001232
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001233 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Denis Ovsienkob4cd2422011-10-22 22:32:26 +04001234 /* Flags check. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001235 if (bgp_attr_flag_invalid (peer, BGP_ATTR_AGGREGATOR, flag))
Denis Ovsienkob4cd2422011-10-22 22:32:26 +04001236 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1237 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1238 startp, total);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001239
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001240 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001241 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001242 wantedlen = 8;
1243
1244 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001245 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001246 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001247 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1248 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001249 startp, total);
paul718e3742002-12-13 20:15:29 +00001250 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001251
1252 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1253 attre->aggregator_as = stream_getl (peer->ibuf);
1254 else
1255 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001256 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001257
1258 /* Set atomic aggregate flag. */
1259 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1260
Paul Jakmab881c702010-11-23 16:35:42 +00001261 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001262}
1263
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001264/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001265static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001266bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001267 struct attr *attr, u_char flag,
1268 as_t *as4_aggregator_as,
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001269 struct in_addr *as4_aggregator_addr,
1270 u_char *startp)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001271{
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001272 bgp_size_t total;
1273
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001274 if (length != 8)
1275 {
1276 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001277 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1278 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1279 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001280 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001281 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1282 /* Flags check. */
1283 if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS4_AGGREGATOR, flag))
1284 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1285 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1286 startp, total);
1287
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001288 *as4_aggregator_as = stream_getl (peer->ibuf);
1289 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1290
1291 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1292
Paul Jakmab881c702010-11-23 16:35:42 +00001293 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001294}
1295
1296/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1297 */
Paul Jakmab881c702010-11-23 16:35:42 +00001298static bgp_attr_parse_ret_t
1299bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001300 struct aspath *as4_path, as_t as4_aggregator,
1301 struct in_addr *as4_aggregator_addr)
1302{
1303 int ignore_as4_path = 0;
1304 struct aspath *newpath;
1305 struct attr_extra *attre = attr->extra;
1306
Paul Jakmab881c702010-11-23 16:35:42 +00001307 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001308 {
1309 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1310 * if given.
1311 * It is worth a warning though, because the peer really
1312 * should not send them
1313 */
1314 if (BGP_DEBUG(as4, AS4))
1315 {
1316 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1317 zlog_debug ("[AS4] %s %s AS4_PATH",
1318 peer->host, "AS4 capable peer, yet it sent");
1319
1320 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1321 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1322 peer->host, "AS4 capable peer, yet it sent");
1323 }
1324
Paul Jakmab881c702010-11-23 16:35:42 +00001325 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001326 }
1327
Paul Jakmab881c702010-11-23 16:35:42 +00001328 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1329 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001330 {
1331 /* Hu? This is not supposed to happen at all!
1332 * got as4_path and no aspath,
1333 * This should already
1334 * have been handled by 'well known attributes missing'
1335 * But... yeah, paranoia
1336 * Take this as a "malformed attribute"
1337 */
1338 zlog (peer->log, LOG_ERR,
1339 "%s BGP not AS4 capable peer sent AS4_PATH but"
1340 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001341 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1342 BGP_NOTIFY_UPDATE_MAL_ATTR,
1343 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001344 }
1345
1346 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1347 * because that may override AS4_PATH
1348 */
1349 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1350 {
Paul Jakmab881c702010-11-23 16:35:42 +00001351 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001352 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001353 assert (attre);
1354
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001355 /* received both.
1356 * if the as_number in aggregator is not AS_TRANS,
1357 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1358 * and the Aggregator shall be taken as
1359 * info on the aggregating node, and the AS_PATH
1360 * shall be taken as the AS_PATH
1361 * otherwise
1362 * the Aggregator shall be ignored and the
1363 * AS4_AGGREGATOR shall be taken as the
1364 * Aggregating node and the AS_PATH is to be
1365 * constructed "as in all other cases"
1366 */
Paul Jakmab881c702010-11-23 16:35:42 +00001367 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001368 {
1369 /* ignore */
1370 if ( BGP_DEBUG(as4, AS4))
1371 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1372 " send AGGREGATOR != AS_TRANS and"
1373 " AS4_AGGREGATOR, so ignore"
1374 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1375 ignore_as4_path = 1;
1376 }
1377 else
1378 {
1379 /* "New_aggregator shall be taken as aggregator" */
1380 attre->aggregator_as = as4_aggregator;
1381 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1382 }
1383 }
1384 else
1385 {
1386 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1387 * That is bogus - but reading the conditions
1388 * we have to handle AS4_AGGREGATOR as if it were
1389 * AGGREGATOR in that case
1390 */
1391 if ( BGP_DEBUG(as4, AS4))
1392 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1393 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1394 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001395 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001396 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1397 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1398 }
1399 }
1400
1401 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001402 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001403 {
1404 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001405 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001406 attr->aspath = aspath_intern (newpath);
1407 }
Paul Jakmab881c702010-11-23 16:35:42 +00001408 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001409}
1410
paul718e3742002-12-13 20:15:29 +00001411/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001412static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001413bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001414 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001415{
Paul Jakmab881c702010-11-23 16:35:42 +00001416 bgp_size_t total
1417 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1418
paul718e3742002-12-13 20:15:29 +00001419 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001420 {
1421 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001422 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001423 }
Paul Jakma0c466382010-12-05 17:17:26 +00001424
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001425 /* Flags check. */
1426 if (bgp_attr_flag_invalid (peer, BGP_ATTR_COMMUNITIES, flag))
1427 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1428 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1429 startp, total);
1430
Paul Jakma0c466382010-12-05 17:17:26 +00001431 attr->community =
1432 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1433
1434 /* XXX: fix community_parse to use stream API and remove this */
1435 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001436
Paul Jakma0c466382010-12-05 17:17:26 +00001437 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001438 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1439 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1440 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001441
paul718e3742002-12-13 20:15:29 +00001442 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1443
Paul Jakmab881c702010-11-23 16:35:42 +00001444 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001445}
1446
1447/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001448static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001449bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienkod595b562011-09-30 15:08:54 +04001450 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001451{
Denis Ovsienkod595b562011-09-30 15:08:54 +04001452 bgp_size_t total;
1453
1454 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1455 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001456 if (bgp_attr_flag_invalid (peer, BGP_ATTR_ORIGINATOR_ID, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001457 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1458 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1459 startp, total);
Denis Ovsienkod595b562011-09-30 15:08:54 +04001460 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001461 if (length != 4)
1462 {
1463 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1464
Paul Jakmab881c702010-11-23 16:35:42 +00001465 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1466 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001467 startp, total);
paul718e3742002-12-13 20:15:29 +00001468 }
1469
Paul Jakmafb982c22007-05-04 20:15:47 +00001470 (bgp_attr_extra_get (attr))->originator_id.s_addr
1471 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001472
1473 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1474
Paul Jakmab881c702010-11-23 16:35:42 +00001475 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001476}
1477
1478/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001479static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001480bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienko0b830442011-09-30 15:12:17 +04001481 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001482{
Denis Ovsienko0b830442011-09-30 15:12:17 +04001483 bgp_size_t total;
1484
1485 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1486 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001487 if (bgp_attr_flag_invalid (peer, BGP_ATTR_CLUSTER_LIST, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001488 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1489 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1490 startp, total);
paul718e3742002-12-13 20:15:29 +00001491 /* Check length. */
1492 if (length % 4)
1493 {
1494 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1495
Paul Jakmab881c702010-11-23 16:35:42 +00001496 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1497 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001498 startp, total);
paul718e3742002-12-13 20:15:29 +00001499 }
1500
Paul Jakmafb982c22007-05-04 20:15:47 +00001501 (bgp_attr_extra_get (attr))->cluster
1502 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001503
1504 /* XXX: Fix cluster_parse to use stream API and then remove this */
1505 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001506
1507 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1508
Paul Jakmab881c702010-11-23 16:35:42 +00001509 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001510}
1511
1512/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001513int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001514bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1515 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001516{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001517 afi_t afi;
1518 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001519 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001520 size_t start;
paul718e3742002-12-13 20:15:29 +00001521 int ret;
1522 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001523 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001524 bgp_size_t total;
1525
1526 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1527 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001528 if (bgp_attr_flag_invalid (peer, BGP_ATTR_MP_REACH_NLRI, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001529 return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag,
1530 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1531 startp, total);
paul718e3742002-12-13 20:15:29 +00001532 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001533 s = BGP_INPUT(peer);
1534 start = stream_get_getp(s);
1535
1536 /* safe to read statically sized header? */
1537#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001538#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001539 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001540 {
1541 zlog_info ("%s: %s sent invalid length, %lu",
1542 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001543 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001544 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001545
paul718e3742002-12-13 20:15:29 +00001546 /* Load AFI, SAFI. */
1547 afi = stream_getw (s);
1548 safi = stream_getc (s);
1549
1550 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001551 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001552
Paul Jakma03292802008-06-07 20:37:10 +00001553 if (LEN_LEFT < attre->mp_nexthop_len)
1554 {
1555 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1556 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001557 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001558 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001559
paul718e3742002-12-13 20:15:29 +00001560 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001561 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001562 {
1563 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001564 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001565 /* Probably needed for RFC 2283 */
1566 if (attr->nexthop.s_addr == 0)
1567 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001568 break;
1569 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001570 stream_getl (s); /* RD high */
1571 stream_getl (s); /* RD low */
1572 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001573 break;
1574#ifdef HAVE_IPV6
1575 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001576 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001577 break;
1578 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001579 stream_get (&attre->mp_nexthop_global, s, 16);
1580 stream_get (&attre->mp_nexthop_local, s, 16);
1581 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001582 {
1583 char buf1[INET6_ADDRSTRLEN];
1584 char buf2[INET6_ADDRSTRLEN];
1585
1586 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001587 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 +00001588 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001589 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001590 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001591 buf2, INET6_ADDRSTRLEN));
1592
Paul Jakmafb982c22007-05-04 20:15:47 +00001593 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001594 }
1595 break;
1596#endif /* HAVE_IPV6 */
1597 default:
Paul Jakma03292802008-06-07 20:37:10 +00001598 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1599 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001600 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001601 }
1602
Paul Jakma03292802008-06-07 20:37:10 +00001603 if (!LEN_LEFT)
1604 {
1605 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1606 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001607 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001608 }
paul718e3742002-12-13 20:15:29 +00001609
Paul Jakma6e4ab122007-04-10 19:36:48 +00001610 {
1611 u_char val;
1612 if ((val = stream_getc (s)))
1613 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1614 peer->host, val);
1615 }
1616
1617 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001618 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001619 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001620 {
1621 zlog_info ("%s: (%s) Failed to read NLRI",
1622 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001623 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001624 }
paul718e3742002-12-13 20:15:29 +00001625
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001626 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001627 {
1628 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001629 if (ret < 0)
1630 {
1631 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1632 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001633 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001634 }
paul718e3742002-12-13 20:15:29 +00001635 }
1636
1637 mp_update->afi = afi;
1638 mp_update->safi = safi;
1639 mp_update->nlri = stream_pnt (s);
1640 mp_update->length = nlri_len;
1641
paul9985f832005-02-09 15:51:56 +00001642 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001643
Paul Jakmab881c702010-11-23 16:35:42 +00001644 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001645#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001646}
1647
1648/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001649int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001650bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1651 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001652 struct bgp_nlri *mp_withdraw)
1653{
1654 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001655 afi_t afi;
1656 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001657 u_int16_t withdraw_len;
1658 int ret;
Denis Ovsienko565b8282011-10-10 21:08:33 +04001659 bgp_size_t total;
1660
1661 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1662 /* Flag checks. */
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001663 if (bgp_attr_flag_invalid (peer, BGP_ATTR_MP_UNREACH_NLRI, flag))
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001664 return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag,
1665 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1666 startp, total);
paul718e3742002-12-13 20:15:29 +00001667
1668 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001669
1670#define BGP_MP_UNREACH_MIN_SIZE 3
1671 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001672 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001673
paul718e3742002-12-13 20:15:29 +00001674 afi = stream_getw (s);
1675 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001676
1677 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001678
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001679 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001680 {
1681 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1682 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001683 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001684 }
1685
1686 mp_withdraw->afi = afi;
1687 mp_withdraw->safi = safi;
1688 mp_withdraw->nlri = stream_pnt (s);
1689 mp_withdraw->length = withdraw_len;
1690
paul9985f832005-02-09 15:51:56 +00001691 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001692
Paul Jakmab881c702010-11-23 16:35:42 +00001693 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001694}
1695
1696/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001697static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001698bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001699 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001700{
Paul Jakmab881c702010-11-23 16:35:42 +00001701 bgp_size_t total
1702 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1703
paul718e3742002-12-13 20:15:29 +00001704 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001705 {
1706 if (attr->extra)
1707 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001708 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001709 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001710 }
Paul Jakma0c466382010-12-05 17:17:26 +00001711
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001712 /* Flags check. */
1713 if (bgp_attr_flag_invalid (peer, BGP_ATTR_EXT_COMMUNITIES, flag))
1714 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag,
1715 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1716 startp, total);
1717
Paul Jakma0c466382010-12-05 17:17:26 +00001718 (bgp_attr_extra_get (attr))->ecommunity =
1719 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1720 /* XXX: fix ecommunity_parse to use stream API */
1721 stream_forward_getp (peer->ibuf, length);
1722
1723 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001724 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1725 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1726 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001727
paul718e3742002-12-13 20:15:29 +00001728 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1729
Paul Jakmab881c702010-11-23 16:35:42 +00001730 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001731}
1732
1733/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001734static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001735bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1736 u_char type, bgp_size_t length, u_char *startp)
1737{
1738 bgp_size_t total;
1739 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001740 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001741
hassof4184462005-02-01 20:13:16 +00001742 if (BGP_DEBUG (normal, NORMAL))
1743 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1744 peer->host, type, length);
1745
paul718e3742002-12-13 20:15:29 +00001746 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001747 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001748 "Unknown attribute type %d length %d is received", type, length);
1749
1750 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001751 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001752
1753 /* Adjest total length to include type and length. */
1754 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1755
1756 /* If any of the mandatory well-known attributes are not recognized,
1757 then the Error Subcode is set to Unrecognized Well-known
1758 Attribute. The Data field contains the unrecognized attribute
1759 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001760 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001761 {
Paul Jakmab881c702010-11-23 16:35:42 +00001762 return bgp_attr_malformed (peer, type, flag,
1763 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1764 startp, total);
paul718e3742002-12-13 20:15:29 +00001765 }
1766
1767 /* Unrecognized non-transitive optional attributes must be quietly
1768 ignored and not passed along to other BGP peers. */
1769 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001770 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001771
1772 /* If a path with recognized transitive optional attribute is
1773 accepted and passed along to other BGP peers and the Partial bit
1774 in the Attribute Flags octet is set to 1 by some previous AS, it
1775 is not set back to 0 by the current AS. */
1776 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1777
1778 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001779 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001780 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001781
Paul Jakmafb982c22007-05-04 20:15:47 +00001782 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001783
1784 if (transit->val)
1785 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1786 transit->length + total);
1787 else
1788 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1789
1790 memcpy (transit->val + transit->length, startp, total);
1791 transit->length += total;
1792
Paul Jakmab881c702010-11-23 16:35:42 +00001793 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001794}
1795
1796/* Read attribute of update packet. This function is called from
1797 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001798bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001799bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1800 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1801{
1802 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001803 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001804 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001805 bgp_size_t length;
1806 u_char *startp, *endp;
1807 u_char *attr_endp;
1808 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001809 /* we need the as4_path only until we have synthesized the as_path with it */
1810 /* same goes for as4_aggregator */
1811 struct aspath *as4_path = NULL;
1812 as_t as4_aggregator = 0;
1813 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001814
1815 /* Initialize bitmap. */
1816 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1817
1818 /* End pointer of BGP attribute. */
1819 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001820
paul718e3742002-12-13 20:15:29 +00001821 /* Get attributes to the end of attribute length. */
1822 while (BGP_INPUT_PNT (peer) < endp)
1823 {
1824 /* Check remaining length check.*/
1825 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1826 {
gdtc29fdba2004-12-09 14:46:46 +00001827 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001828 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001829 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001830 peer->host,
1831 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001832
1833 bgp_notify_send (peer,
1834 BGP_NOTIFY_UPDATE_ERR,
1835 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001836 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001837 }
1838
1839 /* Fetch attribute flag and type. */
1840 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001841 /* "The lower-order four bits of the Attribute Flags octet are
1842 unused. They MUST be zero when sent and MUST be ignored when
1843 received." */
1844 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001845 type = stream_getc (BGP_INPUT (peer));
1846
Paul Jakma370b64a2007-12-22 16:49:52 +00001847 /* Check whether Extended-Length applies and is in bounds */
1848 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1849 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1850 {
1851 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001852 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001853 peer->host,
1854 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1855
1856 bgp_notify_send (peer,
1857 BGP_NOTIFY_UPDATE_ERR,
1858 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001859 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001860 }
1861
paul718e3742002-12-13 20:15:29 +00001862 /* Check extended attribue length bit. */
1863 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1864 length = stream_getw (BGP_INPUT (peer));
1865 else
1866 length = stream_getc (BGP_INPUT (peer));
1867
1868 /* If any attribute appears more than once in the UPDATE
1869 message, then the Error Subcode is set to Malformed Attribute
1870 List. */
1871
1872 if (CHECK_BITMAP (seen, type))
1873 {
1874 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001875 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001876 peer->host, type);
1877
1878 bgp_notify_send (peer,
1879 BGP_NOTIFY_UPDATE_ERR,
1880 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001881 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001882 }
1883
1884 /* Set type to bitmap to check duplicate attribute. `type' is
1885 unsigned char so it never overflow bitmap range. */
1886
1887 SET_BITMAP (seen, type);
1888
1889 /* Overflow check. */
1890 attr_endp = BGP_INPUT_PNT (peer) + length;
1891
1892 if (attr_endp > endp)
1893 {
1894 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001895 "%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 +00001896 bgp_notify_send (peer,
1897 BGP_NOTIFY_UPDATE_ERR,
1898 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001899 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001900 }
1901
1902 /* OK check attribute and store it's value. */
1903 switch (type)
1904 {
1905 case BGP_ATTR_ORIGIN:
1906 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1907 break;
1908 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001909 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001910 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001911 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001912 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001913 break;
paul718e3742002-12-13 20:15:29 +00001914 case BGP_ATTR_NEXT_HOP:
1915 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1916 break;
1917 case BGP_ATTR_MULTI_EXIT_DISC:
1918 ret = bgp_attr_med (peer, length, attr, flag, startp);
1919 break;
1920 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001921 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001922 break;
1923 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001924 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001925 break;
1926 case BGP_ATTR_AGGREGATOR:
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001927 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001928 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001929 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001930 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1931 &as4_aggregator,
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001932 &as4_aggregator_addr, startp);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001933 break;
paul718e3742002-12-13 20:15:29 +00001934 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001935 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001936 break;
1937 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienkod595b562011-09-30 15:08:54 +04001938 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001939 break;
1940 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienko0b830442011-09-30 15:12:17 +04001941 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001942 break;
1943 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001944 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001945 break;
1946 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001947 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001948 break;
1949 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001950 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001951 break;
1952 default:
1953 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1954 break;
1955 }
Paul Jakmab881c702010-11-23 16:35:42 +00001956
1957 /* If hard error occured immediately return to the caller. */
1958 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001959 {
1960 zlog (peer->log, LOG_WARNING,
1961 "%s: Attribute %s, parse error",
1962 peer->host,
1963 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001964 bgp_notify_send (peer,
1965 BGP_NOTIFY_UPDATE_ERR,
1966 BGP_NOTIFY_UPDATE_MAL_ATTR);
1967 if (as4_path)
1968 aspath_unintern (&as4_path);
1969 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001970 }
Paul Jakmab881c702010-11-23 16:35:42 +00001971 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1972 {
1973
1974 zlog (peer->log, LOG_WARNING,
1975 "%s: Attribute %s, parse error - treating as withdrawal",
1976 peer->host,
1977 LOOKUP (attr_str, type));
1978 if (as4_path)
1979 aspath_unintern (&as4_path);
1980 return ret;
1981 }
1982
paul718e3742002-12-13 20:15:29 +00001983 /* Check the fetched length. */
1984 if (BGP_INPUT_PNT (peer) != attr_endp)
1985 {
1986 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001987 "%s: BGP attribute %s, fetch error",
1988 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001989 bgp_notify_send (peer,
1990 BGP_NOTIFY_UPDATE_ERR,
1991 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001992 if (as4_path)
1993 aspath_unintern (&as4_path);
1994 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001995 }
1996 }
1997
1998 /* Check final read pointer is same as end pointer. */
1999 if (BGP_INPUT_PNT (peer) != endp)
2000 {
2001 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04002002 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00002003 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00002004 bgp_notify_send (peer,
2005 BGP_NOTIFY_UPDATE_ERR,
2006 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00002007 if (as4_path)
2008 aspath_unintern (&as4_path);
2009 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002010 }
2011
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002012 /*
2013 * At this place we can see whether we got AS4_PATH and/or
2014 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
2015 * We can not do this before we've read all attributes because
2016 * the as4 handling does not say whether AS4_PATH has to be sent
2017 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
2018 * in relationship to AGGREGATOR.
2019 * So, to be defensive, we are not relying on any order and read
2020 * all attributes first, including these 32bit ones, and now,
2021 * afterwards, we look what and if something is to be done for as4.
2022 */
Paul Jakmab881c702010-11-23 16:35:42 +00002023 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002024 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00002025 {
2026 if (as4_path)
2027 aspath_unintern (&as4_path);
2028 return BGP_ATTR_PARSE_ERROR;
2029 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002030
2031 /* At this stage, we have done all fiddling with as4, and the
2032 * resulting info is in attr->aggregator resp. attr->aspath
2033 * so we can chuck as4_aggregator and as4_path alltogether in
2034 * order to save memory
2035 */
Paul Jakmab881c702010-11-23 16:35:42 +00002036 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002037 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00002038 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002039 /* The flag that we got this is still there, but that does not
2040 * do any trouble
2041 */
2042 }
2043 /*
2044 * The "rest" of the code does nothing with as4_aggregator.
2045 * there is no memory attached specifically which is not part
2046 * of the attr.
2047 * so ignoring just means do nothing.
2048 */
2049 /*
2050 * Finally do the checks on the aspath we did not do yet
2051 * because we waited for a potentially synthesized aspath.
2052 */
Paul Jakmab881c702010-11-23 16:35:42 +00002053 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002054 {
Paul Jakmab881c702010-11-23 16:35:42 +00002055 ret = bgp_attr_aspath_check (peer, attr, flag);
2056 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002057 return ret;
2058 }
2059
paul718e3742002-12-13 20:15:29 +00002060 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002061 if (attr->extra && attr->extra->transit)
2062 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002063
Paul Jakmab881c702010-11-23 16:35:42 +00002064 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002065}
2066
2067/* Well-known attribute check. */
2068int
2069bgp_attr_check (struct peer *peer, struct attr *attr)
2070{
2071 u_char type = 0;
2072
2073 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2074 type = BGP_ATTR_ORIGIN;
2075
2076 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2077 type = BGP_ATTR_AS_PATH;
2078
2079 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2080 type = BGP_ATTR_NEXT_HOP;
2081
2082 if (peer_sort (peer) == BGP_PEER_IBGP
2083 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2084 type = BGP_ATTR_LOCAL_PREF;
2085
2086 if (type)
2087 {
2088 zlog (peer->log, LOG_WARNING,
2089 "%s Missing well-known attribute %d.",
2090 peer->host, type);
2091 bgp_notify_send_with_data (peer,
2092 BGP_NOTIFY_UPDATE_ERR,
2093 BGP_NOTIFY_UPDATE_MISS_ATTR,
2094 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002095 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002096 }
Paul Jakmab881c702010-11-23 16:35:42 +00002097 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002098}
2099
2100int stream_put_prefix (struct stream *, struct prefix *);
2101
2102/* Make attribute packet. */
2103bgp_size_t
2104bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2105 struct stream *s, struct attr *attr, struct prefix *p,
2106 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002107 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002108{
paulfe69a502005-09-10 16:55:02 +00002109 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002110 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002111 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002112 int send_as4_path = 0;
2113 int send_as4_aggregator = 0;
2114 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002115
2116 if (! bgp)
2117 bgp = bgp_get_default ();
2118
2119 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002120 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002121
2122 /* Origin attribute. */
2123 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2124 stream_putc (s, BGP_ATTR_ORIGIN);
2125 stream_putc (s, 1);
2126 stream_putc (s, attr->origin);
2127
2128 /* AS path attribute. */
2129
2130 /* If remote-peer is EBGP */
2131 if (peer_sort (peer) == BGP_PEER_EBGP
2132 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002133 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002134 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002135 {
2136 aspath = aspath_dup (attr->aspath);
2137
2138 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2139 {
2140 /* Strip the confed info, and then stuff our path CONFED_ID
2141 on the front */
2142 aspath = aspath_delete_confed_seq (aspath);
2143 aspath = aspath_add_seq (aspath, bgp->confed_id);
2144 }
2145 else
2146 {
2147 aspath = aspath_add_seq (aspath, peer->local_as);
2148 if (peer->change_local_as)
2149 aspath = aspath_add_seq (aspath, peer->change_local_as);
2150 }
2151 }
2152 else if (peer_sort (peer) == BGP_PEER_CONFED)
2153 {
2154 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2155 aspath = aspath_dup (attr->aspath);
2156 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2157 }
2158 else
2159 aspath = attr->aspath;
2160
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002161 /* If peer is not AS4 capable, then:
2162 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2163 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2164 * types are in it (i.e. exclude them if they are there)
2165 * AND do this only if there is at least one asnum > 65535 in the path!
2166 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2167 * all ASnums > 65535 to BGP_AS_TRANS
2168 */
paul718e3742002-12-13 20:15:29 +00002169
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002170 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2171 stream_putc (s, BGP_ATTR_AS_PATH);
2172 aspath_sizep = stream_get_endp (s);
2173 stream_putw (s, 0);
2174 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2175
2176 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2177 * in the path
2178 */
2179 if (!use32bit && aspath_has_as4 (aspath))
2180 send_as4_path = 1; /* we'll do this later, at the correct place */
2181
paul718e3742002-12-13 20:15:29 +00002182 /* Nexthop attribute. */
2183 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2184 {
2185 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2186 stream_putc (s, BGP_ATTR_NEXT_HOP);
2187 stream_putc (s, 4);
2188 if (safi == SAFI_MPLS_VPN)
2189 {
2190 if (attr->nexthop.s_addr == 0)
2191 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2192 else
2193 stream_put_ipv4 (s, attr->nexthop.s_addr);
2194 }
2195 else
2196 stream_put_ipv4 (s, attr->nexthop.s_addr);
2197 }
2198
2199 /* MED attribute. */
2200 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2201 {
2202 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2203 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2204 stream_putc (s, 4);
2205 stream_putl (s, attr->med);
2206 }
2207
2208 /* Local preference. */
2209 if (peer_sort (peer) == BGP_PEER_IBGP ||
2210 peer_sort (peer) == BGP_PEER_CONFED)
2211 {
2212 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2213 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2214 stream_putc (s, 4);
2215 stream_putl (s, attr->local_pref);
2216 }
2217
2218 /* Atomic aggregate. */
2219 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2220 {
2221 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2222 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2223 stream_putc (s, 0);
2224 }
2225
2226 /* Aggregator. */
2227 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2228 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002229 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002230
2231 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002232 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2233 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002234
2235 if (use32bit)
2236 {
2237 /* AS4 capable peer */
2238 stream_putc (s, 8);
2239 stream_putl (s, attr->extra->aggregator_as);
2240 }
2241 else
2242 {
2243 /* 2-byte AS peer */
2244 stream_putc (s, 6);
2245
2246 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2247 if ( attr->extra->aggregator_as > 65535 )
2248 {
2249 stream_putw (s, BGP_AS_TRANS);
2250
2251 /* we have to send AS4_AGGREGATOR, too.
2252 * we'll do that later in order to send attributes in ascending
2253 * order.
2254 */
2255 send_as4_aggregator = 1;
2256 }
2257 else
2258 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2259 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002260 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002261 }
2262
2263 /* Community attribute. */
2264 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2265 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2266 {
2267 if (attr->community->size * 4 > 255)
2268 {
2269 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2270 stream_putc (s, BGP_ATTR_COMMUNITIES);
2271 stream_putw (s, attr->community->size * 4);
2272 }
2273 else
2274 {
2275 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2276 stream_putc (s, BGP_ATTR_COMMUNITIES);
2277 stream_putc (s, attr->community->size * 4);
2278 }
2279 stream_put (s, attr->community->val, attr->community->size * 4);
2280 }
2281
2282 /* Route Reflector. */
2283 if (peer_sort (peer) == BGP_PEER_IBGP
2284 && from
2285 && peer_sort (from) == BGP_PEER_IBGP)
2286 {
2287 /* Originator ID. */
2288 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2289 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2290 stream_putc (s, 4);
2291
2292 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002293 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002294 else
2295 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002296
2297 /* Cluster list. */
2298 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2299 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2300
Paul Jakma9eda90c2007-08-30 13:36:17 +00002301 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002302 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002303 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002304 /* If this peer configuration's parent BGP has cluster_id. */
2305 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2306 stream_put_in_addr (s, &bgp->cluster_id);
2307 else
2308 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002309 stream_put (s, attr->extra->cluster->list,
2310 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002311 }
2312 else
2313 {
2314 stream_putc (s, 4);
2315 /* If this peer configuration's parent BGP has cluster_id. */
2316 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2317 stream_put_in_addr (s, &bgp->cluster_id);
2318 else
2319 stream_put_in_addr (s, &bgp->router_id);
2320 }
2321 }
2322
2323#ifdef HAVE_IPV6
2324 /* If p is IPv6 address put it into attribute. */
2325 if (p->family == AF_INET6)
2326 {
2327 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002328 struct attr_extra *attre = attr->extra;
2329
2330 assert (attr->extra);
2331
paul718e3742002-12-13 20:15:29 +00002332 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2333 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002334 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002335 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002336 stream_putw (s, AFI_IP6); /* AFI */
2337 stream_putc (s, safi); /* SAFI */
2338
Paul Jakmafb982c22007-05-04 20:15:47 +00002339 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002340
Paul Jakmafb982c22007-05-04 20:15:47 +00002341 if (attre->mp_nexthop_len == 16)
2342 stream_put (s, &attre->mp_nexthop_global, 16);
2343 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002344 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002345 stream_put (s, &attre->mp_nexthop_global, 16);
2346 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002347 }
2348
2349 /* SNPA */
2350 stream_putc (s, 0);
2351
paul718e3742002-12-13 20:15:29 +00002352 /* Prefix write. */
2353 stream_put_prefix (s, p);
2354
2355 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002356 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002357 }
2358#endif /* HAVE_IPV6 */
2359
2360 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2361 {
2362 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002363
2364 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2365 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002366 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002367 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002368 stream_putw (s, AFI_IP); /* AFI */
2369 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2370
2371 stream_putc (s, 4);
2372 stream_put_ipv4 (s, attr->nexthop.s_addr);
2373
2374 /* SNPA */
2375 stream_putc (s, 0);
2376
paul718e3742002-12-13 20:15:29 +00002377 /* Prefix write. */
2378 stream_put_prefix (s, p);
2379
2380 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002381 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002382 }
2383
2384 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2385 {
2386 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002387
2388 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2389 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002390 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002391 stream_putc (s, 0); /* Length of this attribute. */
2392 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002393 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002394
2395 stream_putc (s, 12);
2396 stream_putl (s, 0);
2397 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002398 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002399
2400 /* SNPA */
2401 stream_putc (s, 0);
2402
paul718e3742002-12-13 20:15:29 +00002403 /* Tag, RD, Prefix write. */
2404 stream_putc (s, p->prefixlen + 88);
2405 stream_put (s, tag, 3);
2406 stream_put (s, prd->val, 8);
2407 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2408
2409 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002410 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002411 }
2412
2413 /* Extended Communities attribute. */
2414 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2415 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2416 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002417 struct attr_extra *attre = attr->extra;
2418
2419 assert (attre);
2420
2421 if (peer_sort (peer) == BGP_PEER_IBGP
2422 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002423 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002424 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002425 {
2426 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2427 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002428 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002429 }
2430 else
2431 {
2432 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2433 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002434 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002435 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002436 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002437 }
2438 else
2439 {
paul5228ad22004-06-04 17:58:18 +00002440 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002441 int tbit;
2442 int ecom_tr_size = 0;
2443 int i;
2444
Paul Jakmafb982c22007-05-04 20:15:47 +00002445 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002446 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002447 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002448 tbit = *pnt;
2449
2450 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2451 continue;
2452
2453 ecom_tr_size++;
2454 }
2455
2456 if (ecom_tr_size)
2457 {
2458 if (ecom_tr_size * 8 > 255)
2459 {
2460 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2461 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2462 stream_putw (s, ecom_tr_size * 8);
2463 }
2464 else
2465 {
2466 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2467 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2468 stream_putc (s, ecom_tr_size * 8);
2469 }
2470
Paul Jakmafb982c22007-05-04 20:15:47 +00002471 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002472 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002473 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002474 tbit = *pnt;
2475
2476 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2477 continue;
2478
2479 stream_put (s, pnt, 8);
2480 }
2481 }
paul718e3742002-12-13 20:15:29 +00002482 }
paul718e3742002-12-13 20:15:29 +00002483 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002484
2485 if ( send_as4_path )
2486 {
2487 /* If the peer is NOT As4 capable, AND */
2488 /* there are ASnums > 65535 in path THEN
2489 * give out AS4_PATH */
2490
2491 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2492 * path segments!
2493 * Hm, I wonder... confederation things *should* only be at
2494 * the beginning of an aspath, right? Then we should use
2495 * aspath_delete_confed_seq for this, because it is already
2496 * there! (JK)
2497 * Folks, talk to me: what is reasonable here!?
2498 */
2499 aspath = aspath_delete_confed_seq (aspath);
2500
2501 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2502 stream_putc (s, BGP_ATTR_AS4_PATH);
2503 aspath_sizep = stream_get_endp (s);
2504 stream_putw (s, 0);
2505 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2506 }
2507
2508 if (aspath != attr->aspath)
2509 aspath_free (aspath);
2510
2511 if ( send_as4_aggregator )
2512 {
2513 assert (attr->extra);
2514
2515 /* send AS4_AGGREGATOR, at this place */
2516 /* this section of code moved here in order to ensure the correct
2517 * *ascending* order of attributes
2518 */
2519 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2520 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2521 stream_putc (s, 8);
2522 stream_putl (s, attr->extra->aggregator_as);
2523 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2524 }
Paul Jakma41367172007-08-06 15:24:51 +00002525
paul718e3742002-12-13 20:15:29 +00002526 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002527 if (attr->extra && attr->extra->transit)
2528 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002529
2530 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002531 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002532}
2533
2534bgp_size_t
2535bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2536 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002537 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002538{
2539 unsigned long cp;
2540 unsigned long attrlen_pnt;
2541 bgp_size_t size;
2542
paul9985f832005-02-09 15:51:56 +00002543 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002544
2545 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2546 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2547
paul9985f832005-02-09 15:51:56 +00002548 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002549 stream_putc (s, 0); /* Length of this attribute. */
2550
2551 stream_putw (s, family2afi (p->family));
2552
2553 if (safi == SAFI_MPLS_VPN)
2554 {
2555 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002556 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002557
2558 /* prefix. */
2559 stream_putc (s, p->prefixlen + 88);
2560 stream_put (s, tag, 3);
2561 stream_put (s, prd->val, 8);
2562 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2563 }
2564 else
2565 {
2566 /* SAFI */
2567 stream_putc (s, safi);
2568
2569 /* prefix */
2570 stream_put_prefix (s, p);
2571 }
2572
2573 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002574 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002575 stream_putc_at (s, attrlen_pnt, size);
2576
paul9985f832005-02-09 15:51:56 +00002577 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002578}
2579
2580/* Initialization of attribute. */
2581void
paulfe69a502005-09-10 16:55:02 +00002582bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002583{
paul718e3742002-12-13 20:15:29 +00002584 aspath_init ();
2585 attrhash_init ();
2586 community_init ();
2587 ecommunity_init ();
2588 cluster_init ();
2589 transit_init ();
2590}
2591
Chris Caputo228da422009-07-18 05:44:03 +00002592void
2593bgp_attr_finish (void)
2594{
2595 aspath_finish ();
2596 attrhash_finish ();
2597 community_finish ();
2598 ecommunity_finish ();
2599 cluster_finish ();
2600 transit_finish ();
2601}
2602
paul718e3742002-12-13 20:15:29 +00002603/* Make attribute packet. */
2604void
paula3845922003-10-18 01:30:50 +00002605bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2606 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002607{
2608 unsigned long cp;
2609 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002610 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002611 struct aspath *aspath;
2612
2613 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002614 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002615
2616 /* Place holder of length. */
2617 stream_putw (s, 0);
2618
2619 /* Origin attribute. */
2620 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2621 stream_putc (s, BGP_ATTR_ORIGIN);
2622 stream_putc (s, 1);
2623 stream_putc (s, attr->origin);
2624
2625 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002626
2627 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2628 stream_putc (s, BGP_ATTR_AS_PATH);
2629 aspath_lenp = stream_get_endp (s);
2630 stream_putw (s, 0);
2631
2632 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002633
2634 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002635 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2636 if(prefix != NULL
2637#ifdef HAVE_IPV6
2638 && prefix->family != AF_INET6
2639#endif /* HAVE_IPV6 */
2640 )
2641 {
2642 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2643 stream_putc (s, BGP_ATTR_NEXT_HOP);
2644 stream_putc (s, 4);
2645 stream_put_ipv4 (s, attr->nexthop.s_addr);
2646 }
paul718e3742002-12-13 20:15:29 +00002647
2648 /* MED attribute. */
2649 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2650 {
2651 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2652 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2653 stream_putc (s, 4);
2654 stream_putl (s, attr->med);
2655 }
2656
2657 /* Local preference. */
2658 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2659 {
2660 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2661 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2662 stream_putc (s, 4);
2663 stream_putl (s, attr->local_pref);
2664 }
2665
2666 /* Atomic aggregate. */
2667 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2668 {
2669 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2670 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2671 stream_putc (s, 0);
2672 }
2673
2674 /* Aggregator. */
2675 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2676 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002677 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002678 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2679 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002680 stream_putc (s, 8);
2681 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002682 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002683 }
2684
2685 /* Community attribute. */
2686 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2687 {
2688 if (attr->community->size * 4 > 255)
2689 {
2690 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2691 stream_putc (s, BGP_ATTR_COMMUNITIES);
2692 stream_putw (s, attr->community->size * 4);
2693 }
2694 else
2695 {
2696 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2697 stream_putc (s, BGP_ATTR_COMMUNITIES);
2698 stream_putc (s, attr->community->size * 4);
2699 }
2700 stream_put (s, attr->community->val, attr->community->size * 4);
2701 }
2702
paula3845922003-10-18 01:30:50 +00002703#ifdef HAVE_IPV6
2704 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002705 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2706 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002707 {
2708 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002709 struct attr_extra *attre = attr->extra;
2710
paula3845922003-10-18 01:30:50 +00002711 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2712 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002713 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002714
2715 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002716 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002717 stream_putw(s, AFI_IP6); /* AFI */
2718 stream_putc(s, SAFI_UNICAST); /* SAFI */
2719
2720 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002721 stream_putc(s, attre->mp_nexthop_len);
2722 stream_put(s, &attre->mp_nexthop_global, 16);
2723 if (attre->mp_nexthop_len == 32)
2724 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002725
2726 /* SNPA */
2727 stream_putc(s, 0);
2728
2729 /* Prefix */
2730 stream_put_prefix(s, prefix);
2731
2732 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002733 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002734 }
2735#endif /* HAVE_IPV6 */
2736
paul718e3742002-12-13 20:15:29 +00002737 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002738 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002739 stream_putw_at (s, cp, len);
2740}