blob: b013c23f37e70a2bfee1d1439ee1a7a279632e5d [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
paul718e3742002-12-13 20:15:29 +0000802/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000803static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000804bgp_attr_origin (struct peer *peer, bgp_size_t length,
805 struct attr *attr, u_char flag, u_char *startp)
806{
807 bgp_size_t total;
808
809 /* total is entire attribute length include Attribute Flags (1),
810 Attribute Type code (1) and Attribute length (1 or 2). */
811 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
812
813 /* If any recognized attribute has Attribute Flags that conflict
814 with the Attribute Type Code, then the Error Subcode is set to
815 Attribute Flags Error. The Data field contains the erroneous
816 attribute (type, length and value). */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400817 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400818 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400819 bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGIN, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400820 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
821 }
paul718e3742002-12-13 20:15:29 +0000822
823 /* If any recognized attribute has Attribute Length that conflicts
824 with the expected length (based on the attribute type code), then
825 the Error Subcode is set to Attribute Length Error. The Data
826 field contains the erroneous attribute (type, length and
827 value). */
828 if (length != 1)
829 {
830 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
831 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000832 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
833 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
834 startp, total);
paul718e3742002-12-13 20:15:29 +0000835 }
836
837 /* Fetch origin attribute. */
838 attr->origin = stream_getc (BGP_INPUT (peer));
839
840 /* If the ORIGIN attribute has an undefined value, then the Error
841 Subcode is set to Invalid Origin Attribute. The Data field
842 contains the unrecognized attribute (type, length and value). */
843 if ((attr->origin != BGP_ORIGIN_IGP)
844 && (attr->origin != BGP_ORIGIN_EGP)
845 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
846 {
847 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
848 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000849 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
850 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
851 startp, total);
paul718e3742002-12-13 20:15:29 +0000852 }
853
854 /* Set oring attribute flag. */
855 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
856
857 return 0;
858}
Paul Jakmaab005292010-11-27 22:48:34 +0000859
860/* Parse AS path information. This function is wrapper of
861 aspath_parse. */
862static int
paul718e3742002-12-13 20:15:29 +0000863bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000864 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000865{
Paul Jakmaab005292010-11-27 22:48:34 +0000866 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000867
Paul Jakmaab005292010-11-27 22:48:34 +0000868 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000869
Paul Jakmaab005292010-11-27 22:48:34 +0000870 /* Flag check. */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400871 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
872 {
873 zlog (peer->log, LOG_ERR,
874 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
875 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
876 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
877 startp, total);
878 }
879
Paul Jakmaab005292010-11-27 22:48:34 +0000880 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
881 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000882 {
883 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000884 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000885 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
886 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
887 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400888 }
Paul Jakmaab005292010-11-27 22:48:34 +0000889
890 /*
891 * peer with AS4 => will get 4Byte ASnums
892 * otherwise, will get 16 Bit
893 */
894 attr->aspath = aspath_parse (peer->ibuf, length,
895 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
896
897 /* In case of IBGP, length will be zero. */
898 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000899 {
Paul Jakmab881c702010-11-23 16:35:42 +0000900 zlog (peer->log, LOG_ERR,
901 "Malformed AS path from %s, length is %d",
902 peer->host, length);
903 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
904 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
905 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000906 }
Chris Hallcddb8112010-08-09 22:31:37 +0400907
Paul Jakmaab005292010-11-27 22:48:34 +0000908 /* Set aspath attribute flag. */
909 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000910
Paul Jakmab881c702010-11-23 16:35:42 +0000911 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000912}
913
Paul Jakmab881c702010-11-23 16:35:42 +0000914static bgp_attr_parse_ret_t
915bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000916{
917 /* These checks were part of bgp_attr_aspath, but with
918 * as4 we should to check aspath things when
919 * aspath synthesizing with as4_path has already taken place.
920 * Otherwise we check ASPATH and use the synthesized thing, and that is
921 * not right.
922 * So do the checks later, i.e. here
923 */
924 struct bgp *bgp = peer->bgp;
925 struct aspath *aspath;
926
paul718e3742002-12-13 20:15:29 +0000927 bgp = peer->bgp;
928
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300929 /* Confederation sanity check. */
930 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
931 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
932 {
933 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000934 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
935 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
936 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300937 }
938
paul718e3742002-12-13 20:15:29 +0000939 /* First AS check for EBGP. */
940 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
941 {
942 if (peer_sort (peer) == BGP_PEER_EBGP
943 && ! aspath_firstas_check (attr->aspath, peer->as))
944 {
945 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400946 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000947 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
948 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
949 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000950 }
951 }
952
953 /* local-as prepend */
954 if (peer->change_local_as &&
955 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
956 {
957 aspath = aspath_dup (attr->aspath);
958 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000959 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000960 attr->aspath = aspath_intern (aspath);
961 }
962
Paul Jakmab881c702010-11-23 16:35:42 +0000963 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000964}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000965
Paul Jakmaab005292010-11-27 22:48:34 +0000966/* Parse AS4 path information. This function is another wrapper of
967 aspath_parse. */
968static int
Paul Jakmab881c702010-11-23 16:35:42 +0000969bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
970 struct attr *attr, u_char flag, u_char *startp,
971 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000972{
Paul Jakmab881c702010-11-23 16:35:42 +0000973 bgp_size_t total;
974
975 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
976
977 /* Flag check. */
978 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
979 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
980 {
981 zlog (peer->log, LOG_ERR,
982 "As4-Path attribute flag isn't optional/transitive %d", flag);
983 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
984 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
985 startp, total);
986 }
987
Paul Jakmaab005292010-11-27 22:48:34 +0000988 *as4_path = aspath_parse (peer->ibuf, length, 1);
989
Paul Jakmab881c702010-11-23 16:35:42 +0000990 /* In case of IBGP, length will be zero. */
991 if (!*as4_path)
992 {
993 zlog (peer->log, LOG_ERR,
994 "Malformed AS4 path from %s, length is %d",
995 peer->host, length);
996 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
997 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
998 NULL, 0);
999 }
1000
Paul Jakmaab005292010-11-27 22:48:34 +00001001 /* Set aspath attribute flag. */
1002 if (as4_path)
1003 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1004
Paul Jakmab881c702010-11-23 16:35:42 +00001005 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001006}
1007
paul718e3742002-12-13 20:15:29 +00001008/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001009static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001010bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
1011 struct attr *attr, u_char flag, u_char *startp)
1012{
1013 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001014 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001015
1016 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1017
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001018 /* Flags check. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001019 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001020 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001021 bgp_attr_flags_diagnose (peer, BGP_ATTR_NEXT_HOP, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001022 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1023 }
paul718e3742002-12-13 20:15:29 +00001024
1025 /* Check nexthop attribute length. */
1026 if (length != 4)
1027 {
1028 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1029 length);
1030
Paul Jakmab881c702010-11-23 16:35:42 +00001031 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1032 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1033 startp, total);
paul718e3742002-12-13 20:15:29 +00001034 }
1035
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001036 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1037 attribute must result in a NOTIFICATION message (this is implemented below).
1038 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1039 logged locally (this is implemented somewhere else). The UPDATE message
1040 gets ignored in any of these cases. */
1041 nexthop_n = stream_get_ipv4 (peer->ibuf);
1042 nexthop_h = ntohl (nexthop_n);
1043 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1044 {
1045 char buf[INET_ADDRSTRLEN];
1046 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1047 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1048 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1049 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1050 startp, total);
1051 }
1052
1053 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001054 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1055
Paul Jakmab881c702010-11-23 16:35:42 +00001056 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001057}
1058
1059/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001060static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001061bgp_attr_med (struct peer *peer, bgp_size_t length,
1062 struct attr *attr, u_char flag, u_char *startp)
1063{
1064 bgp_size_t total;
1065
1066 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1067
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001068 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001069 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001070 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001071 bgp_attr_flags_diagnose (peer, BGP_ATTR_MULTI_EXIT_DISC, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001072 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1073 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1074 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001075 }
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001076
paul718e3742002-12-13 20:15:29 +00001077 /* Length check. */
1078 if (length != 4)
1079 {
1080 zlog (peer->log, LOG_ERR,
1081 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001082
1083 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1084 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1085 startp, total);
paul718e3742002-12-13 20:15:29 +00001086 }
1087
1088 attr->med = stream_getl (peer->ibuf);
1089
1090 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1091
Paul Jakmab881c702010-11-23 16:35:42 +00001092 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001093}
1094
1095/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001096static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001097bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001098 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001099{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001100 bgp_size_t total;
1101
1102 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1103 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001104 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001105 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001106 bgp_attr_flags_diagnose (peer, BGP_ATTR_LOCAL_PREF, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001107 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
1108 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1109 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001110 }
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001111 /* Length check. */
1112 if (length != 4)
1113 {
1114 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001115 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001116 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1117 startp, total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001118 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001119
paul718e3742002-12-13 20:15:29 +00001120 /* If it is contained in an UPDATE message that is received from an
1121 external peer, then this attribute MUST be ignored by the
1122 receiving speaker. */
1123 if (peer_sort (peer) == BGP_PEER_EBGP)
1124 {
paul9985f832005-02-09 15:51:56 +00001125 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001126 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001127 }
1128
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001129 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001130
1131 /* Set atomic aggregate flag. */
1132 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1133
Paul Jakmab881c702010-11-23 16:35:42 +00001134 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001135}
1136
1137/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001138static int
paul718e3742002-12-13 20:15:29 +00001139bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001140 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001141{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001142 bgp_size_t total;
1143
1144 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1145 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001146 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001147 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001148 bgp_attr_flags_diagnose (peer, BGP_ATTR_ATOMIC_AGGREGATE, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001149 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1150 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1151 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001152 }
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001153
1154 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001155 if (length != 0)
1156 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001157 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001158 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1159 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001160 startp, total);
paul718e3742002-12-13 20:15:29 +00001161 }
1162
1163 /* Set atomic aggregate flag. */
1164 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1165
Paul Jakmab881c702010-11-23 16:35:42 +00001166 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001167}
1168
1169/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001170static int
paul718e3742002-12-13 20:15:29 +00001171bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001172 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001173{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001174 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001175 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001176 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001177
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001178 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Denis Ovsienkob4cd2422011-10-22 22:32:26 +04001179 /* Flags check. */
1180 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1181 {
1182 zlog (peer->log, LOG_ERR,
1183 "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag);
1184 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1185 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1186 startp, total);
1187 }
1188 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1189 {
1190 zlog (peer->log, LOG_ERR,
1191 "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag);
1192 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1193 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1194 startp, total);
1195 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001196 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001197 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001198 wantedlen = 8;
1199
1200 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001201 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001202 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001203 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1204 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001205 startp, total);
paul718e3742002-12-13 20:15:29 +00001206 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001207
1208 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1209 attre->aggregator_as = stream_getl (peer->ibuf);
1210 else
1211 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001212 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001213
1214 /* Set atomic aggregate flag. */
1215 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1216
Paul Jakmab881c702010-11-23 16:35:42 +00001217 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001218}
1219
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001220/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001221static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001222bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001223 struct attr *attr, u_char flag,
1224 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001225 struct in_addr *as4_aggregator_addr)
1226{
1227 if (length != 8)
1228 {
1229 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001230 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1231 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1232 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001233 }
1234 *as4_aggregator_as = stream_getl (peer->ibuf);
1235 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1236
1237 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1238
Paul Jakmab881c702010-11-23 16:35:42 +00001239 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001240}
1241
1242/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1243 */
Paul Jakmab881c702010-11-23 16:35:42 +00001244static bgp_attr_parse_ret_t
1245bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001246 struct aspath *as4_path, as_t as4_aggregator,
1247 struct in_addr *as4_aggregator_addr)
1248{
1249 int ignore_as4_path = 0;
1250 struct aspath *newpath;
1251 struct attr_extra *attre = attr->extra;
1252
Paul Jakmab881c702010-11-23 16:35:42 +00001253 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001254 {
1255 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1256 * if given.
1257 * It is worth a warning though, because the peer really
1258 * should not send them
1259 */
1260 if (BGP_DEBUG(as4, AS4))
1261 {
1262 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1263 zlog_debug ("[AS4] %s %s AS4_PATH",
1264 peer->host, "AS4 capable peer, yet it sent");
1265
1266 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1267 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1268 peer->host, "AS4 capable peer, yet it sent");
1269 }
1270
Paul Jakmab881c702010-11-23 16:35:42 +00001271 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001272 }
1273
Paul Jakmab881c702010-11-23 16:35:42 +00001274 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1275 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001276 {
1277 /* Hu? This is not supposed to happen at all!
1278 * got as4_path and no aspath,
1279 * This should already
1280 * have been handled by 'well known attributes missing'
1281 * But... yeah, paranoia
1282 * Take this as a "malformed attribute"
1283 */
1284 zlog (peer->log, LOG_ERR,
1285 "%s BGP not AS4 capable peer sent AS4_PATH but"
1286 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001287 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1288 BGP_NOTIFY_UPDATE_MAL_ATTR,
1289 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001290 }
1291
1292 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1293 * because that may override AS4_PATH
1294 */
1295 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1296 {
Paul Jakmab881c702010-11-23 16:35:42 +00001297 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001298 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001299 assert (attre);
1300
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001301 /* received both.
1302 * if the as_number in aggregator is not AS_TRANS,
1303 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1304 * and the Aggregator shall be taken as
1305 * info on the aggregating node, and the AS_PATH
1306 * shall be taken as the AS_PATH
1307 * otherwise
1308 * the Aggregator shall be ignored and the
1309 * AS4_AGGREGATOR shall be taken as the
1310 * Aggregating node and the AS_PATH is to be
1311 * constructed "as in all other cases"
1312 */
Paul Jakmab881c702010-11-23 16:35:42 +00001313 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001314 {
1315 /* ignore */
1316 if ( BGP_DEBUG(as4, AS4))
1317 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1318 " send AGGREGATOR != AS_TRANS and"
1319 " AS4_AGGREGATOR, so ignore"
1320 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1321 ignore_as4_path = 1;
1322 }
1323 else
1324 {
1325 /* "New_aggregator shall be taken as aggregator" */
1326 attre->aggregator_as = as4_aggregator;
1327 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1328 }
1329 }
1330 else
1331 {
1332 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1333 * That is bogus - but reading the conditions
1334 * we have to handle AS4_AGGREGATOR as if it were
1335 * AGGREGATOR in that case
1336 */
1337 if ( BGP_DEBUG(as4, AS4))
1338 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1339 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1340 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001341 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001342 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1343 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1344 }
1345 }
1346
1347 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001348 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001349 {
1350 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001351 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001352 attr->aspath = aspath_intern (newpath);
1353 }
Paul Jakmab881c702010-11-23 16:35:42 +00001354 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001355}
1356
paul718e3742002-12-13 20:15:29 +00001357/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001358static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001359bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001360 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001361{
Paul Jakmab881c702010-11-23 16:35:42 +00001362 bgp_size_t total
1363 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1364
paul718e3742002-12-13 20:15:29 +00001365 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001366 {
1367 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001368 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001369 }
Paul Jakma0c466382010-12-05 17:17:26 +00001370
1371 attr->community =
1372 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1373
1374 /* XXX: fix community_parse to use stream API and remove this */
1375 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001376
Paul Jakma0c466382010-12-05 17:17:26 +00001377 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001378 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1379 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1380 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001381
paul718e3742002-12-13 20:15:29 +00001382 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1383
Paul Jakmab881c702010-11-23 16:35:42 +00001384 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001385}
1386
1387/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001388static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001389bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienkod595b562011-09-30 15:08:54 +04001390 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001391{
Denis Ovsienkod595b562011-09-30 15:08:54 +04001392 bgp_size_t total;
1393
1394 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1395 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001396 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkod595b562011-09-30 15:08:54 +04001397 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001398 bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGINATOR_ID, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001399 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1400 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1401 startp, total);
Denis Ovsienkod595b562011-09-30 15:08:54 +04001402 }
1403 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001404 if (length != 4)
1405 {
1406 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1407
Paul Jakmab881c702010-11-23 16:35:42 +00001408 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1409 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001410 startp, total);
paul718e3742002-12-13 20:15:29 +00001411 }
1412
Paul Jakmafb982c22007-05-04 20:15:47 +00001413 (bgp_attr_extra_get (attr))->originator_id.s_addr
1414 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001415
1416 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1417
Paul Jakmab881c702010-11-23 16:35:42 +00001418 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001419}
1420
1421/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001422static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001423bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienko0b830442011-09-30 15:12:17 +04001424 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001425{
Denis Ovsienko0b830442011-09-30 15:12:17 +04001426 bgp_size_t total;
1427
1428 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1429 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001430 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko0b830442011-09-30 15:12:17 +04001431 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001432 bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001433 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1434 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1435 startp, total);
Denis Ovsienko0b830442011-09-30 15:12:17 +04001436 }
paul718e3742002-12-13 20:15:29 +00001437 /* Check length. */
1438 if (length % 4)
1439 {
1440 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1441
Paul Jakmab881c702010-11-23 16:35:42 +00001442 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1443 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001444 startp, total);
paul718e3742002-12-13 20:15:29 +00001445 }
1446
Paul Jakmafb982c22007-05-04 20:15:47 +00001447 (bgp_attr_extra_get (attr))->cluster
1448 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001449
1450 /* XXX: Fix cluster_parse to use stream API and then remove this */
1451 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001452
1453 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1454
Paul Jakmab881c702010-11-23 16:35:42 +00001455 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001456}
1457
1458/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001459int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001460bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1461 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001462{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001463 afi_t afi;
1464 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001465 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001466 size_t start;
paul718e3742002-12-13 20:15:29 +00001467 int ret;
1468 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001469 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001470 bgp_size_t total;
1471
1472 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1473 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001474 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko565b8282011-10-10 21:08:33 +04001475 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001476 bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_REACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001477 return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag,
1478 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1479 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001480 }
paul718e3742002-12-13 20:15:29 +00001481 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001482 s = BGP_INPUT(peer);
1483 start = stream_get_getp(s);
1484
1485 /* safe to read statically sized header? */
1486#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001487#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001488 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001489 {
1490 zlog_info ("%s: %s sent invalid length, %lu",
1491 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001492 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001493 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001494
paul718e3742002-12-13 20:15:29 +00001495 /* Load AFI, SAFI. */
1496 afi = stream_getw (s);
1497 safi = stream_getc (s);
1498
1499 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001500 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001501
Paul Jakma03292802008-06-07 20:37:10 +00001502 if (LEN_LEFT < attre->mp_nexthop_len)
1503 {
1504 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1505 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001506 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001507 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001508
paul718e3742002-12-13 20:15:29 +00001509 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001510 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001511 {
1512 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001513 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001514 /* Probably needed for RFC 2283 */
1515 if (attr->nexthop.s_addr == 0)
1516 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001517 break;
1518 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001519 stream_getl (s); /* RD high */
1520 stream_getl (s); /* RD low */
1521 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001522 break;
1523#ifdef HAVE_IPV6
1524 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001525 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001526 break;
1527 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001528 stream_get (&attre->mp_nexthop_global, s, 16);
1529 stream_get (&attre->mp_nexthop_local, s, 16);
1530 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001531 {
1532 char buf1[INET6_ADDRSTRLEN];
1533 char buf2[INET6_ADDRSTRLEN];
1534
1535 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001536 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 +00001537 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001538 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001539 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001540 buf2, INET6_ADDRSTRLEN));
1541
Paul Jakmafb982c22007-05-04 20:15:47 +00001542 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001543 }
1544 break;
1545#endif /* HAVE_IPV6 */
1546 default:
Paul Jakma03292802008-06-07 20:37:10 +00001547 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1548 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001549 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001550 }
1551
Paul Jakma03292802008-06-07 20:37:10 +00001552 if (!LEN_LEFT)
1553 {
1554 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1555 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001556 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001557 }
paul718e3742002-12-13 20:15:29 +00001558
Paul Jakma6e4ab122007-04-10 19:36:48 +00001559 {
1560 u_char val;
1561 if ((val = stream_getc (s)))
1562 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1563 peer->host, val);
1564 }
1565
1566 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001567 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001568 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001569 {
1570 zlog_info ("%s: (%s) Failed to read NLRI",
1571 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001572 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001573 }
paul718e3742002-12-13 20:15:29 +00001574
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001575 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001576 {
1577 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001578 if (ret < 0)
1579 {
1580 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1581 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001582 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001583 }
paul718e3742002-12-13 20:15:29 +00001584 }
1585
1586 mp_update->afi = afi;
1587 mp_update->safi = safi;
1588 mp_update->nlri = stream_pnt (s);
1589 mp_update->length = nlri_len;
1590
paul9985f832005-02-09 15:51:56 +00001591 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001592
Paul Jakmab881c702010-11-23 16:35:42 +00001593 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001594#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001595}
1596
1597/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001598int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001599bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1600 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001601 struct bgp_nlri *mp_withdraw)
1602{
1603 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001604 afi_t afi;
1605 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001606 u_int16_t withdraw_len;
1607 int ret;
Denis Ovsienko565b8282011-10-10 21:08:33 +04001608 bgp_size_t total;
1609
1610 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1611 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001612 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko565b8282011-10-10 21:08:33 +04001613 {
Denis Ovsienkoafcb7672011-10-23 22:32:44 +04001614 bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_UNREACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001615 return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag,
1616 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1617 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001618 }
paul718e3742002-12-13 20:15:29 +00001619
1620 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001621
1622#define BGP_MP_UNREACH_MIN_SIZE 3
1623 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001624 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001625
paul718e3742002-12-13 20:15:29 +00001626 afi = stream_getw (s);
1627 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001628
1629 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001630
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001631 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001632 {
1633 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1634 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001635 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001636 }
1637
1638 mp_withdraw->afi = afi;
1639 mp_withdraw->safi = safi;
1640 mp_withdraw->nlri = stream_pnt (s);
1641 mp_withdraw->length = withdraw_len;
1642
paul9985f832005-02-09 15:51:56 +00001643 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001644
Paul Jakmab881c702010-11-23 16:35:42 +00001645 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001646}
1647
1648/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001649static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001650bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001651 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001652{
Paul Jakmab881c702010-11-23 16:35:42 +00001653 bgp_size_t total
1654 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1655
paul718e3742002-12-13 20:15:29 +00001656 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001657 {
1658 if (attr->extra)
1659 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001660 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001661 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001662 }
Paul Jakma0c466382010-12-05 17:17:26 +00001663
1664 (bgp_attr_extra_get (attr))->ecommunity =
1665 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1666 /* XXX: fix ecommunity_parse to use stream API */
1667 stream_forward_getp (peer->ibuf, length);
1668
1669 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001670 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1671 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1672 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001673
paul718e3742002-12-13 20:15:29 +00001674 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1675
Paul Jakmab881c702010-11-23 16:35:42 +00001676 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001677}
1678
1679/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001680static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001681bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1682 u_char type, bgp_size_t length, u_char *startp)
1683{
1684 bgp_size_t total;
1685 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001686 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001687
hassof4184462005-02-01 20:13:16 +00001688 if (BGP_DEBUG (normal, NORMAL))
1689 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1690 peer->host, type, length);
1691
paul718e3742002-12-13 20:15:29 +00001692 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001693 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001694 "Unknown attribute type %d length %d is received", type, length);
1695
1696 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001697 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001698
1699 /* Adjest total length to include type and length. */
1700 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1701
1702 /* If any of the mandatory well-known attributes are not recognized,
1703 then the Error Subcode is set to Unrecognized Well-known
1704 Attribute. The Data field contains the unrecognized attribute
1705 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001706 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001707 {
Paul Jakmab881c702010-11-23 16:35:42 +00001708 return bgp_attr_malformed (peer, type, flag,
1709 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1710 startp, total);
paul718e3742002-12-13 20:15:29 +00001711 }
1712
1713 /* Unrecognized non-transitive optional attributes must be quietly
1714 ignored and not passed along to other BGP peers. */
1715 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001716 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001717
1718 /* If a path with recognized transitive optional attribute is
1719 accepted and passed along to other BGP peers and the Partial bit
1720 in the Attribute Flags octet is set to 1 by some previous AS, it
1721 is not set back to 0 by the current AS. */
1722 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1723
1724 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001725 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001726 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001727
Paul Jakmafb982c22007-05-04 20:15:47 +00001728 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001729
1730 if (transit->val)
1731 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1732 transit->length + total);
1733 else
1734 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1735
1736 memcpy (transit->val + transit->length, startp, total);
1737 transit->length += total;
1738
Paul Jakmab881c702010-11-23 16:35:42 +00001739 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001740}
1741
1742/* Read attribute of update packet. This function is called from
1743 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001744bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001745bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1746 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1747{
1748 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001749 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001750 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001751 bgp_size_t length;
1752 u_char *startp, *endp;
1753 u_char *attr_endp;
1754 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001755 /* we need the as4_path only until we have synthesized the as_path with it */
1756 /* same goes for as4_aggregator */
1757 struct aspath *as4_path = NULL;
1758 as_t as4_aggregator = 0;
1759 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001760
1761 /* Initialize bitmap. */
1762 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1763
1764 /* End pointer of BGP attribute. */
1765 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001766
paul718e3742002-12-13 20:15:29 +00001767 /* Get attributes to the end of attribute length. */
1768 while (BGP_INPUT_PNT (peer) < endp)
1769 {
1770 /* Check remaining length check.*/
1771 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1772 {
gdtc29fdba2004-12-09 14:46:46 +00001773 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001774 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001775 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001776 peer->host,
1777 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001778
1779 bgp_notify_send (peer,
1780 BGP_NOTIFY_UPDATE_ERR,
1781 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001782 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001783 }
1784
1785 /* Fetch attribute flag and type. */
1786 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001787 /* "The lower-order four bits of the Attribute Flags octet are
1788 unused. They MUST be zero when sent and MUST be ignored when
1789 received." */
1790 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001791 type = stream_getc (BGP_INPUT (peer));
1792
Paul Jakma370b64a2007-12-22 16:49:52 +00001793 /* Check whether Extended-Length applies and is in bounds */
1794 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1795 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1796 {
1797 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001798 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001799 peer->host,
1800 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1801
1802 bgp_notify_send (peer,
1803 BGP_NOTIFY_UPDATE_ERR,
1804 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001805 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001806 }
1807
paul718e3742002-12-13 20:15:29 +00001808 /* Check extended attribue length bit. */
1809 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1810 length = stream_getw (BGP_INPUT (peer));
1811 else
1812 length = stream_getc (BGP_INPUT (peer));
1813
1814 /* If any attribute appears more than once in the UPDATE
1815 message, then the Error Subcode is set to Malformed Attribute
1816 List. */
1817
1818 if (CHECK_BITMAP (seen, type))
1819 {
1820 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001821 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001822 peer->host, type);
1823
1824 bgp_notify_send (peer,
1825 BGP_NOTIFY_UPDATE_ERR,
1826 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001827 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001828 }
1829
1830 /* Set type to bitmap to check duplicate attribute. `type' is
1831 unsigned char so it never overflow bitmap range. */
1832
1833 SET_BITMAP (seen, type);
1834
1835 /* Overflow check. */
1836 attr_endp = BGP_INPUT_PNT (peer) + length;
1837
1838 if (attr_endp > endp)
1839 {
1840 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001841 "%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 +00001842 bgp_notify_send (peer,
1843 BGP_NOTIFY_UPDATE_ERR,
1844 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001845 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001846 }
1847
1848 /* OK check attribute and store it's value. */
1849 switch (type)
1850 {
1851 case BGP_ATTR_ORIGIN:
1852 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1853 break;
1854 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001855 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001856 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001857 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001858 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001859 break;
paul718e3742002-12-13 20:15:29 +00001860 case BGP_ATTR_NEXT_HOP:
1861 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1862 break;
1863 case BGP_ATTR_MULTI_EXIT_DISC:
1864 ret = bgp_attr_med (peer, length, attr, flag, startp);
1865 break;
1866 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001867 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001868 break;
1869 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001870 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001871 break;
1872 case BGP_ATTR_AGGREGATOR:
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001873 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001874 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001875 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001876 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1877 &as4_aggregator,
1878 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001879 break;
paul718e3742002-12-13 20:15:29 +00001880 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001881 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001882 break;
1883 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienkod595b562011-09-30 15:08:54 +04001884 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001885 break;
1886 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienko0b830442011-09-30 15:12:17 +04001887 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001888 break;
1889 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001890 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001891 break;
1892 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001893 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001894 break;
1895 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001896 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001897 break;
1898 default:
1899 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1900 break;
1901 }
Paul Jakmab881c702010-11-23 16:35:42 +00001902
1903 /* If hard error occured immediately return to the caller. */
1904 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001905 {
1906 zlog (peer->log, LOG_WARNING,
1907 "%s: Attribute %s, parse error",
1908 peer->host,
1909 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001910 bgp_notify_send (peer,
1911 BGP_NOTIFY_UPDATE_ERR,
1912 BGP_NOTIFY_UPDATE_MAL_ATTR);
1913 if (as4_path)
1914 aspath_unintern (&as4_path);
1915 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001916 }
Paul Jakmab881c702010-11-23 16:35:42 +00001917 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1918 {
1919
1920 zlog (peer->log, LOG_WARNING,
1921 "%s: Attribute %s, parse error - treating as withdrawal",
1922 peer->host,
1923 LOOKUP (attr_str, type));
1924 if (as4_path)
1925 aspath_unintern (&as4_path);
1926 return ret;
1927 }
1928
paul718e3742002-12-13 20:15:29 +00001929 /* Check the fetched length. */
1930 if (BGP_INPUT_PNT (peer) != attr_endp)
1931 {
1932 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001933 "%s: BGP attribute %s, fetch error",
1934 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001935 bgp_notify_send (peer,
1936 BGP_NOTIFY_UPDATE_ERR,
1937 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001938 if (as4_path)
1939 aspath_unintern (&as4_path);
1940 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001941 }
1942 }
1943
1944 /* Check final read pointer is same as end pointer. */
1945 if (BGP_INPUT_PNT (peer) != endp)
1946 {
1947 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001948 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001949 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001950 bgp_notify_send (peer,
1951 BGP_NOTIFY_UPDATE_ERR,
1952 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001953 if (as4_path)
1954 aspath_unintern (&as4_path);
1955 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001956 }
1957
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001958 /*
1959 * At this place we can see whether we got AS4_PATH and/or
1960 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1961 * We can not do this before we've read all attributes because
1962 * the as4 handling does not say whether AS4_PATH has to be sent
1963 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1964 * in relationship to AGGREGATOR.
1965 * So, to be defensive, we are not relying on any order and read
1966 * all attributes first, including these 32bit ones, and now,
1967 * afterwards, we look what and if something is to be done for as4.
1968 */
Paul Jakmab881c702010-11-23 16:35:42 +00001969 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001970 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001971 {
1972 if (as4_path)
1973 aspath_unintern (&as4_path);
1974 return BGP_ATTR_PARSE_ERROR;
1975 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001976
1977 /* At this stage, we have done all fiddling with as4, and the
1978 * resulting info is in attr->aggregator resp. attr->aspath
1979 * so we can chuck as4_aggregator and as4_path alltogether in
1980 * order to save memory
1981 */
Paul Jakmab881c702010-11-23 16:35:42 +00001982 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001983 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001984 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001985 /* The flag that we got this is still there, but that does not
1986 * do any trouble
1987 */
1988 }
1989 /*
1990 * The "rest" of the code does nothing with as4_aggregator.
1991 * there is no memory attached specifically which is not part
1992 * of the attr.
1993 * so ignoring just means do nothing.
1994 */
1995 /*
1996 * Finally do the checks on the aspath we did not do yet
1997 * because we waited for a potentially synthesized aspath.
1998 */
Paul Jakmab881c702010-11-23 16:35:42 +00001999 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002000 {
Paul Jakmab881c702010-11-23 16:35:42 +00002001 ret = bgp_attr_aspath_check (peer, attr, flag);
2002 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002003 return ret;
2004 }
2005
paul718e3742002-12-13 20:15:29 +00002006 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002007 if (attr->extra && attr->extra->transit)
2008 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002009
Paul Jakmab881c702010-11-23 16:35:42 +00002010 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002011}
2012
2013/* Well-known attribute check. */
2014int
2015bgp_attr_check (struct peer *peer, struct attr *attr)
2016{
2017 u_char type = 0;
2018
2019 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2020 type = BGP_ATTR_ORIGIN;
2021
2022 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2023 type = BGP_ATTR_AS_PATH;
2024
2025 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2026 type = BGP_ATTR_NEXT_HOP;
2027
2028 if (peer_sort (peer) == BGP_PEER_IBGP
2029 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2030 type = BGP_ATTR_LOCAL_PREF;
2031
2032 if (type)
2033 {
2034 zlog (peer->log, LOG_WARNING,
2035 "%s Missing well-known attribute %d.",
2036 peer->host, type);
2037 bgp_notify_send_with_data (peer,
2038 BGP_NOTIFY_UPDATE_ERR,
2039 BGP_NOTIFY_UPDATE_MISS_ATTR,
2040 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002041 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002042 }
Paul Jakmab881c702010-11-23 16:35:42 +00002043 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002044}
2045
2046int stream_put_prefix (struct stream *, struct prefix *);
2047
2048/* Make attribute packet. */
2049bgp_size_t
2050bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2051 struct stream *s, struct attr *attr, struct prefix *p,
2052 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002053 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002054{
paulfe69a502005-09-10 16:55:02 +00002055 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002056 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002057 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002058 int send_as4_path = 0;
2059 int send_as4_aggregator = 0;
2060 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002061
2062 if (! bgp)
2063 bgp = bgp_get_default ();
2064
2065 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002066 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002067
2068 /* Origin attribute. */
2069 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2070 stream_putc (s, BGP_ATTR_ORIGIN);
2071 stream_putc (s, 1);
2072 stream_putc (s, attr->origin);
2073
2074 /* AS path attribute. */
2075
2076 /* If remote-peer is EBGP */
2077 if (peer_sort (peer) == BGP_PEER_EBGP
2078 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002079 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002080 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002081 {
2082 aspath = aspath_dup (attr->aspath);
2083
2084 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2085 {
2086 /* Strip the confed info, and then stuff our path CONFED_ID
2087 on the front */
2088 aspath = aspath_delete_confed_seq (aspath);
2089 aspath = aspath_add_seq (aspath, bgp->confed_id);
2090 }
2091 else
2092 {
2093 aspath = aspath_add_seq (aspath, peer->local_as);
2094 if (peer->change_local_as)
2095 aspath = aspath_add_seq (aspath, peer->change_local_as);
2096 }
2097 }
2098 else if (peer_sort (peer) == BGP_PEER_CONFED)
2099 {
2100 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2101 aspath = aspath_dup (attr->aspath);
2102 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2103 }
2104 else
2105 aspath = attr->aspath;
2106
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002107 /* If peer is not AS4 capable, then:
2108 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2109 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2110 * types are in it (i.e. exclude them if they are there)
2111 * AND do this only if there is at least one asnum > 65535 in the path!
2112 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2113 * all ASnums > 65535 to BGP_AS_TRANS
2114 */
paul718e3742002-12-13 20:15:29 +00002115
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002116 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2117 stream_putc (s, BGP_ATTR_AS_PATH);
2118 aspath_sizep = stream_get_endp (s);
2119 stream_putw (s, 0);
2120 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2121
2122 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2123 * in the path
2124 */
2125 if (!use32bit && aspath_has_as4 (aspath))
2126 send_as4_path = 1; /* we'll do this later, at the correct place */
2127
paul718e3742002-12-13 20:15:29 +00002128 /* Nexthop attribute. */
2129 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2130 {
2131 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2132 stream_putc (s, BGP_ATTR_NEXT_HOP);
2133 stream_putc (s, 4);
2134 if (safi == SAFI_MPLS_VPN)
2135 {
2136 if (attr->nexthop.s_addr == 0)
2137 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2138 else
2139 stream_put_ipv4 (s, attr->nexthop.s_addr);
2140 }
2141 else
2142 stream_put_ipv4 (s, attr->nexthop.s_addr);
2143 }
2144
2145 /* MED attribute. */
2146 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2147 {
2148 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2149 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2150 stream_putc (s, 4);
2151 stream_putl (s, attr->med);
2152 }
2153
2154 /* Local preference. */
2155 if (peer_sort (peer) == BGP_PEER_IBGP ||
2156 peer_sort (peer) == BGP_PEER_CONFED)
2157 {
2158 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2159 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2160 stream_putc (s, 4);
2161 stream_putl (s, attr->local_pref);
2162 }
2163
2164 /* Atomic aggregate. */
2165 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2166 {
2167 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2168 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2169 stream_putc (s, 0);
2170 }
2171
2172 /* Aggregator. */
2173 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2174 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002175 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002176
2177 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002178 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2179 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002180
2181 if (use32bit)
2182 {
2183 /* AS4 capable peer */
2184 stream_putc (s, 8);
2185 stream_putl (s, attr->extra->aggregator_as);
2186 }
2187 else
2188 {
2189 /* 2-byte AS peer */
2190 stream_putc (s, 6);
2191
2192 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2193 if ( attr->extra->aggregator_as > 65535 )
2194 {
2195 stream_putw (s, BGP_AS_TRANS);
2196
2197 /* we have to send AS4_AGGREGATOR, too.
2198 * we'll do that later in order to send attributes in ascending
2199 * order.
2200 */
2201 send_as4_aggregator = 1;
2202 }
2203 else
2204 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2205 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002206 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002207 }
2208
2209 /* Community attribute. */
2210 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2211 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2212 {
2213 if (attr->community->size * 4 > 255)
2214 {
2215 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2216 stream_putc (s, BGP_ATTR_COMMUNITIES);
2217 stream_putw (s, attr->community->size * 4);
2218 }
2219 else
2220 {
2221 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2222 stream_putc (s, BGP_ATTR_COMMUNITIES);
2223 stream_putc (s, attr->community->size * 4);
2224 }
2225 stream_put (s, attr->community->val, attr->community->size * 4);
2226 }
2227
2228 /* Route Reflector. */
2229 if (peer_sort (peer) == BGP_PEER_IBGP
2230 && from
2231 && peer_sort (from) == BGP_PEER_IBGP)
2232 {
2233 /* Originator ID. */
2234 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2235 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2236 stream_putc (s, 4);
2237
2238 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002239 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002240 else
2241 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002242
2243 /* Cluster list. */
2244 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2245 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2246
Paul Jakma9eda90c2007-08-30 13:36:17 +00002247 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002248 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002249 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002250 /* If this peer configuration's parent BGP has cluster_id. */
2251 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2252 stream_put_in_addr (s, &bgp->cluster_id);
2253 else
2254 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002255 stream_put (s, attr->extra->cluster->list,
2256 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002257 }
2258 else
2259 {
2260 stream_putc (s, 4);
2261 /* If this peer configuration's parent BGP has cluster_id. */
2262 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2263 stream_put_in_addr (s, &bgp->cluster_id);
2264 else
2265 stream_put_in_addr (s, &bgp->router_id);
2266 }
2267 }
2268
2269#ifdef HAVE_IPV6
2270 /* If p is IPv6 address put it into attribute. */
2271 if (p->family == AF_INET6)
2272 {
2273 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 struct attr_extra *attre = attr->extra;
2275
2276 assert (attr->extra);
2277
paul718e3742002-12-13 20:15:29 +00002278 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2279 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002280 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002281 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002282 stream_putw (s, AFI_IP6); /* AFI */
2283 stream_putc (s, safi); /* SAFI */
2284
Paul Jakmafb982c22007-05-04 20:15:47 +00002285 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002286
Paul Jakmafb982c22007-05-04 20:15:47 +00002287 if (attre->mp_nexthop_len == 16)
2288 stream_put (s, &attre->mp_nexthop_global, 16);
2289 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002290 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002291 stream_put (s, &attre->mp_nexthop_global, 16);
2292 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002293 }
2294
2295 /* SNPA */
2296 stream_putc (s, 0);
2297
paul718e3742002-12-13 20:15:29 +00002298 /* Prefix write. */
2299 stream_put_prefix (s, p);
2300
2301 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002302 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002303 }
2304#endif /* HAVE_IPV6 */
2305
2306 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2307 {
2308 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002309
2310 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2311 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002312 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002313 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002314 stream_putw (s, AFI_IP); /* AFI */
2315 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2316
2317 stream_putc (s, 4);
2318 stream_put_ipv4 (s, attr->nexthop.s_addr);
2319
2320 /* SNPA */
2321 stream_putc (s, 0);
2322
paul718e3742002-12-13 20:15:29 +00002323 /* Prefix write. */
2324 stream_put_prefix (s, p);
2325
2326 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002327 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002328 }
2329
2330 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2331 {
2332 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002333
2334 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2335 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002336 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002337 stream_putc (s, 0); /* Length of this attribute. */
2338 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002339 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002340
2341 stream_putc (s, 12);
2342 stream_putl (s, 0);
2343 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002344 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002345
2346 /* SNPA */
2347 stream_putc (s, 0);
2348
paul718e3742002-12-13 20:15:29 +00002349 /* Tag, RD, Prefix write. */
2350 stream_putc (s, p->prefixlen + 88);
2351 stream_put (s, tag, 3);
2352 stream_put (s, prd->val, 8);
2353 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
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
2359 /* Extended Communities attribute. */
2360 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2361 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2362 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002363 struct attr_extra *attre = attr->extra;
2364
2365 assert (attre);
2366
2367 if (peer_sort (peer) == BGP_PEER_IBGP
2368 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002369 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002370 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002371 {
2372 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2373 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002374 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002375 }
2376 else
2377 {
2378 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2379 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002380 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002381 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002382 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002383 }
2384 else
2385 {
paul5228ad22004-06-04 17:58:18 +00002386 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002387 int tbit;
2388 int ecom_tr_size = 0;
2389 int i;
2390
Paul Jakmafb982c22007-05-04 20:15:47 +00002391 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002392 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002393 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002394 tbit = *pnt;
2395
2396 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2397 continue;
2398
2399 ecom_tr_size++;
2400 }
2401
2402 if (ecom_tr_size)
2403 {
2404 if (ecom_tr_size * 8 > 255)
2405 {
2406 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2407 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2408 stream_putw (s, ecom_tr_size * 8);
2409 }
2410 else
2411 {
2412 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2413 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2414 stream_putc (s, ecom_tr_size * 8);
2415 }
2416
Paul Jakmafb982c22007-05-04 20:15:47 +00002417 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002418 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002419 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002420 tbit = *pnt;
2421
2422 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2423 continue;
2424
2425 stream_put (s, pnt, 8);
2426 }
2427 }
paul718e3742002-12-13 20:15:29 +00002428 }
paul718e3742002-12-13 20:15:29 +00002429 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002430
2431 if ( send_as4_path )
2432 {
2433 /* If the peer is NOT As4 capable, AND */
2434 /* there are ASnums > 65535 in path THEN
2435 * give out AS4_PATH */
2436
2437 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2438 * path segments!
2439 * Hm, I wonder... confederation things *should* only be at
2440 * the beginning of an aspath, right? Then we should use
2441 * aspath_delete_confed_seq for this, because it is already
2442 * there! (JK)
2443 * Folks, talk to me: what is reasonable here!?
2444 */
2445 aspath = aspath_delete_confed_seq (aspath);
2446
2447 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2448 stream_putc (s, BGP_ATTR_AS4_PATH);
2449 aspath_sizep = stream_get_endp (s);
2450 stream_putw (s, 0);
2451 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2452 }
2453
2454 if (aspath != attr->aspath)
2455 aspath_free (aspath);
2456
2457 if ( send_as4_aggregator )
2458 {
2459 assert (attr->extra);
2460
2461 /* send AS4_AGGREGATOR, at this place */
2462 /* this section of code moved here in order to ensure the correct
2463 * *ascending* order of attributes
2464 */
2465 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2466 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2467 stream_putc (s, 8);
2468 stream_putl (s, attr->extra->aggregator_as);
2469 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2470 }
Paul Jakma41367172007-08-06 15:24:51 +00002471
paul718e3742002-12-13 20:15:29 +00002472 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002473 if (attr->extra && attr->extra->transit)
2474 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002475
2476 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002477 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002478}
2479
2480bgp_size_t
2481bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2482 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002483 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002484{
2485 unsigned long cp;
2486 unsigned long attrlen_pnt;
2487 bgp_size_t size;
2488
paul9985f832005-02-09 15:51:56 +00002489 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002490
2491 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2492 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2493
paul9985f832005-02-09 15:51:56 +00002494 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002495 stream_putc (s, 0); /* Length of this attribute. */
2496
2497 stream_putw (s, family2afi (p->family));
2498
2499 if (safi == SAFI_MPLS_VPN)
2500 {
2501 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002502 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002503
2504 /* prefix. */
2505 stream_putc (s, p->prefixlen + 88);
2506 stream_put (s, tag, 3);
2507 stream_put (s, prd->val, 8);
2508 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2509 }
2510 else
2511 {
2512 /* SAFI */
2513 stream_putc (s, safi);
2514
2515 /* prefix */
2516 stream_put_prefix (s, p);
2517 }
2518
2519 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002520 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002521 stream_putc_at (s, attrlen_pnt, size);
2522
paul9985f832005-02-09 15:51:56 +00002523 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002524}
2525
2526/* Initialization of attribute. */
2527void
paulfe69a502005-09-10 16:55:02 +00002528bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002529{
paul718e3742002-12-13 20:15:29 +00002530 aspath_init ();
2531 attrhash_init ();
2532 community_init ();
2533 ecommunity_init ();
2534 cluster_init ();
2535 transit_init ();
2536}
2537
Chris Caputo228da422009-07-18 05:44:03 +00002538void
2539bgp_attr_finish (void)
2540{
2541 aspath_finish ();
2542 attrhash_finish ();
2543 community_finish ();
2544 ecommunity_finish ();
2545 cluster_finish ();
2546 transit_finish ();
2547}
2548
paul718e3742002-12-13 20:15:29 +00002549/* Make attribute packet. */
2550void
paula3845922003-10-18 01:30:50 +00002551bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2552 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002553{
2554 unsigned long cp;
2555 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002556 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002557 struct aspath *aspath;
2558
2559 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002560 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002561
2562 /* Place holder of length. */
2563 stream_putw (s, 0);
2564
2565 /* Origin attribute. */
2566 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2567 stream_putc (s, BGP_ATTR_ORIGIN);
2568 stream_putc (s, 1);
2569 stream_putc (s, attr->origin);
2570
2571 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002572
2573 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2574 stream_putc (s, BGP_ATTR_AS_PATH);
2575 aspath_lenp = stream_get_endp (s);
2576 stream_putw (s, 0);
2577
2578 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002579
2580 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002581 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2582 if(prefix != NULL
2583#ifdef HAVE_IPV6
2584 && prefix->family != AF_INET6
2585#endif /* HAVE_IPV6 */
2586 )
2587 {
2588 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2589 stream_putc (s, BGP_ATTR_NEXT_HOP);
2590 stream_putc (s, 4);
2591 stream_put_ipv4 (s, attr->nexthop.s_addr);
2592 }
paul718e3742002-12-13 20:15:29 +00002593
2594 /* MED attribute. */
2595 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2596 {
2597 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2598 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2599 stream_putc (s, 4);
2600 stream_putl (s, attr->med);
2601 }
2602
2603 /* Local preference. */
2604 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2605 {
2606 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2607 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2608 stream_putc (s, 4);
2609 stream_putl (s, attr->local_pref);
2610 }
2611
2612 /* Atomic aggregate. */
2613 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2614 {
2615 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2616 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2617 stream_putc (s, 0);
2618 }
2619
2620 /* Aggregator. */
2621 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2622 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002623 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002624 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2625 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002626 stream_putc (s, 8);
2627 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002628 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002629 }
2630
2631 /* Community attribute. */
2632 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2633 {
2634 if (attr->community->size * 4 > 255)
2635 {
2636 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2637 stream_putc (s, BGP_ATTR_COMMUNITIES);
2638 stream_putw (s, attr->community->size * 4);
2639 }
2640 else
2641 {
2642 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2643 stream_putc (s, BGP_ATTR_COMMUNITIES);
2644 stream_putc (s, attr->community->size * 4);
2645 }
2646 stream_put (s, attr->community->val, attr->community->size * 4);
2647 }
2648
paula3845922003-10-18 01:30:50 +00002649#ifdef HAVE_IPV6
2650 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002651 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2652 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002653 {
2654 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002655 struct attr_extra *attre = attr->extra;
2656
paula3845922003-10-18 01:30:50 +00002657 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2658 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002659 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002660
2661 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002662 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002663 stream_putw(s, AFI_IP6); /* AFI */
2664 stream_putc(s, SAFI_UNICAST); /* SAFI */
2665
2666 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002667 stream_putc(s, attre->mp_nexthop_len);
2668 stream_put(s, &attre->mp_nexthop_global, 16);
2669 if (attre->mp_nexthop_len == 32)
2670 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002671
2672 /* SNPA */
2673 stream_putc(s, 0);
2674
2675 /* Prefix */
2676 stream_put_prefix(s, prefix);
2677
2678 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002679 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002680 }
2681#endif /* HAVE_IPV6 */
2682
paul718e3742002-12-13 20:15:29 +00002683 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002684 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002685 stream_putw_at (s, cp, len);
2686}