blob: 7c0f6cc6de090fe943c38054d0c24290844b8957 [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;
Jorge Boncompte [DTI2]e16a4132012-05-07 16:52:57 +0000562
Paul Jakma03e214c2007-04-29 18:31:07 +0000563 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000564
565 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000566 bgp_attr_extra_free (&attr);
567
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000568 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000569 return new;
570}
571
572struct attr *
573bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
574 struct aspath *aspath,
575 struct community *community, int as_set)
576{
577 struct attr attr;
578 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000580
581 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000582 attre = bgp_attr_extra_get (&attr);
583
paul718e3742002-12-13 20:15:29 +0000584 /* Origin attribute. */
585 attr.origin = origin;
586 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
587
588 /* AS path attribute. */
589 if (aspath)
590 attr.aspath = aspath_intern (aspath);
591 else
592 attr.aspath = aspath_empty ();
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
594
595 /* Next hop attribute. */
596 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
597
598 if (community)
599 {
600 attr.community = community;
601 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
602 }
603
Paul Jakmafb982c22007-05-04 20:15:47 +0000604 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000605#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000606 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000607#endif
608 if (! as_set)
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
610 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
611 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000612 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000613 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000614 attre->aggregator_as = bgp->as;
615 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000616
617 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000618 bgp_attr_extra_free (&attr);
619
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000620 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000621 return new;
622}
623
Paul Jakmab881c702010-11-23 16:35:42 +0000624/* Unintern just the sub-components of the attr, but not the attr */
625void
626bgp_attr_unintern_sub (struct attr *attr)
627{
628 /* aspath refcount shoud be decrement. */
629 if (attr->aspath)
630 aspath_unintern (&attr->aspath);
631 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
632
633 if (attr->community)
634 community_unintern (&attr->community);
635 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
636
637 if (attr->extra)
638 {
639 if (attr->extra->ecommunity)
640 ecommunity_unintern (&attr->extra->ecommunity);
641 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
642
643 if (attr->extra->cluster)
644 cluster_unintern (attr->extra->cluster);
645 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
646
647 if (attr->extra->transit)
648 transit_unintern (attr->extra->transit);
649 }
650}
651
paul718e3742002-12-13 20:15:29 +0000652/* Free bgp attribute and aspath. */
653void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000654bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000655{
656 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000657 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000658
paul718e3742002-12-13 20:15:29 +0000659 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000660 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000661
662 tmp = *(*attr);
663
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000664 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000665 {
Paul Jakmab881c702010-11-23 16:35:42 +0000666 tmp.extra = bgp_attr_extra_new ();
667 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000668 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000669
paul718e3742002-12-13 20:15:29 +0000670 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000671 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000672 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000673 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000674 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000675 bgp_attr_extra_free (*attr);
676 XFREE (MTYPE_ATTR, *attr);
677 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000678 }
679
Paul Jakmab881c702010-11-23 16:35:42 +0000680 bgp_attr_unintern_sub (&tmp);
Oleg A. Arkhangelskyce0af6f2011-12-03 15:18:19 +0400681 bgp_attr_extra_free (&tmp);
paul718e3742002-12-13 20:15:29 +0000682}
683
684void
685bgp_attr_flush (struct attr *attr)
686{
687 if (attr->aspath && ! attr->aspath->refcnt)
688 aspath_free (attr->aspath);
689 if (attr->community && ! attr->community->refcnt)
690 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000691 if (attr->extra)
692 {
693 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000694
Paul Jakmafb982c22007-05-04 20:15:47 +0000695 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000696 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000697 if (attre->cluster && ! attre->cluster->refcnt)
698 cluster_free (attre->cluster);
699 if (attre->transit && ! attre->transit->refcnt)
700 transit_free (attre->transit);
701 }
paul718e3742002-12-13 20:15:29 +0000702}
703
Paul Jakmab881c702010-11-23 16:35:42 +0000704/* Implement draft-scudder-idr-optional-transitive behaviour and
705 * avoid resetting sessions for malformed attributes which are
706 * are partial/optional and hence where the error likely was not
707 * introduced by the sending neighbour.
708 */
709static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000710bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
711 bgp_size_t length)
Paul Jakmab881c702010-11-23 16:35:42 +0000712{
Paul Jakma835315b2012-01-18 12:28:30 +0000713 struct peer *const peer = args->peer;
714 const u_int8_t flags = args->flags;
715 /* startp and length must be special-cased, as whether or not to
716 * send the attribute data with the NOTIFY depends on the error,
717 * the caller therefore signals this with the seperate length argument
718 */
Paul Jakmabd471fe2012-03-15 11:30:00 +0000719 u_char *notify_datap = (length > 0 ? args->startp : NULL);
Paul Jakma835315b2012-01-18 12:28:30 +0000720
Paul Jakmab881c702010-11-23 16:35:42 +0000721 /* Only relax error handling for eBGP peers */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000722 if (peer->sort != BGP_PEER_EBGP)
Paul Jakmab881c702010-11-23 16:35:42 +0000723 {
724 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000725 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000726 return BGP_ATTR_PARSE_ERROR;
727
728 }
729
Paul Jakmabd471fe2012-03-15 11:30:00 +0000730 /* Adjust the stream getp to the end of the attribute, in case we can
731 * still proceed but the caller hasn't read all the attribute.
732 */
733 stream_set_getp (BGP_INPUT (peer),
734 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
735 + args->total);
736
Paul Jakma835315b2012-01-18 12:28:30 +0000737 switch (args->type) {
Paul Jakmafa61e162012-03-25 21:31:47 +0100738 /* where an attribute is relatively inconsequential, e.g. it does not
739 * affect route selection, and can be safely ignored, then any such
740 * attributes which are malformed should just be ignored and the route
741 * processed as normal.
Paul Jakmab881c702010-11-23 16:35:42 +0000742 */
743 case BGP_ATTR_AS4_AGGREGATOR:
744 case BGP_ATTR_AGGREGATOR:
745 case BGP_ATTR_ATOMIC_AGGREGATE:
746 return BGP_ATTR_PARSE_PROCEED;
747
748 /* Core attributes, particularly ones which may influence route
Paul Jakmafa61e162012-03-25 21:31:47 +0100749 * selection, should always cause session resets
Paul Jakmab881c702010-11-23 16:35:42 +0000750 */
751 case BGP_ATTR_ORIGIN:
752 case BGP_ATTR_AS_PATH:
753 case BGP_ATTR_NEXT_HOP:
754 case BGP_ATTR_MULTI_EXIT_DISC:
755 case BGP_ATTR_LOCAL_PREF:
756 case BGP_ATTR_COMMUNITIES:
757 case BGP_ATTR_ORIGINATOR_ID:
758 case BGP_ATTR_CLUSTER_LIST:
759 case BGP_ATTR_MP_REACH_NLRI:
760 case BGP_ATTR_MP_UNREACH_NLRI:
761 case BGP_ATTR_EXT_COMMUNITIES:
762 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
Paul Jakmabd471fe2012-03-15 11:30:00 +0000763 notify_datap, length);
Paul Jakmab881c702010-11-23 16:35:42 +0000764 return BGP_ATTR_PARSE_ERROR;
765 }
766
767 /* Partial optional attributes that are malformed should not cause
768 * the whole session to be reset. Instead treat it as a withdrawal
769 * of the routes, if possible.
770 */
Paul Jakma835315b2012-01-18 12:28:30 +0000771 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
772 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
773 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
Paul Jakmab881c702010-11-23 16:35:42 +0000774 return BGP_ATTR_PARSE_WITHDRAW;
775
776 /* default to reset */
777 return BGP_ATTR_PARSE_ERROR;
778}
779
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400780/* Find out what is wrong with the path attribute flag bits and log the error.
781 "Flag bits" here stand for Optional, Transitive and Partial, but not for
782 Extended Length. Checking O/T/P bits at once implies, that the attribute
783 being diagnosed is defined by RFC as either a "well-known" or an "optional,
784 non-transitive" attribute. */
785static void
Paul Jakma835315b2012-01-18 12:28:30 +0000786bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
787 u_int8_t desired_flags /* how RFC says it must be */
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400788)
789{
790 u_char seen = 0, i;
Paul Jakma835315b2012-01-18 12:28:30 +0000791 u_char real_flags = args->flags;
792 const u_int8_t attr_code = args->type;
793
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400794 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
795 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
796 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
797 if
798 (
799 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
800 CHECK_FLAG (real_flags, attr_flag_str[i].key)
801 )
802 {
Paul Jakma835315b2012-01-18 12:28:30 +0000803 zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400804 LOOKUP (attr_str, attr_code),
805 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
806 attr_flag_str[i].str);
807 seen = 1;
808 }
Paul Jakmafa5831e2012-03-27 11:54:04 +0100809 if (!seen)
810 {
811 zlog (args->peer->log, LOG_DEBUG,
812 "Strange, %s called for attr %s, but no problem found with flags"
813 " (real flags 0x%x, desired 0x%x)",
814 __func__, LOOKUP (attr_str, attr_code),
815 real_flags, desired_flags);
816 }
Denis Ovsienkoafcb7672011-10-23 22:32:44 +0400817}
818
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000819/* Required flags for attributes. EXTLEN will be masked off when testing,
820 * as will PARTIAL for optional+transitive attributes.
821 */
822const u_int8_t attr_flags_values [] = {
823 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
824 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
825 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
826 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
827 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
828 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
829 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
830 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
831 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
832 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
833 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
834 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
835 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
836 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
837 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
838};
839static const size_t attr_flags_values_max =
840 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
841
842static int
Paul Jakma835315b2012-01-18 12:28:30 +0000843bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000844{
845 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
Paul Jakma835315b2012-01-18 12:28:30 +0000846 const u_int8_t flags = args->flags;
847 const u_int8_t attr_code = args->type;
848 struct peer *const peer = args->peer;
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000849
850 /* there may be attributes we don't know about */
851 if (attr_code > attr_flags_values_max)
852 return 0;
853 if (attr_flags_values[attr_code] == 0)
854 return 0;
855
856 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
857 * 1."
858 */
859 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
860 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
861 {
862 zlog (peer->log, LOG_ERR,
863 "%s well-known attributes must have transitive flag set (%x)",
864 LOOKUP (attr_str, attr_code), flags);
865 return 1;
866 }
867
868 /* "For well-known attributes and for optional non-transitive attributes,
869 * the Partial bit MUST be set to 0."
870 */
871 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
872 {
873 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
874 {
875 zlog (peer->log, LOG_ERR,
876 "%s well-known attribute "
877 "must NOT have the partial flag set (%x)",
878 LOOKUP (attr_str, attr_code), flags);
879 return 1;
880 }
881 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
882 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
883 {
884 zlog (peer->log, LOG_ERR,
885 "%s optional + transitive attribute "
886 "must NOT have the partial flag set (%x)",
887 LOOKUP (attr_str, attr_code), flags);
888 return 1;
889 }
890 }
891
892 /* Optional transitive attributes may go through speakers that don't
893 * reocgnise them and set the Partial bit.
894 */
895 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
896 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
897 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
898
Paul Jakma683f2b82012-03-23 14:58:45 +0000899 if ((flags & ~mask)
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000900 == attr_flags_values[attr_code])
901 return 0;
902
Paul Jakma835315b2012-01-18 12:28:30 +0000903 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
Paul Jakma3ecab4c2012-01-17 13:31:33 +0000904 return 1;
905}
906
paul718e3742002-12-13 20:15:29 +0000907/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000908static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000909bgp_attr_origin (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000910{
Paul Jakma835315b2012-01-18 12:28:30 +0000911 struct peer *const peer = args->peer;
912 struct attr *const attr = args->attr;
913 const bgp_size_t length = args->length;
914
paul718e3742002-12-13 20:15:29 +0000915 /* If any recognized attribute has Attribute Length that conflicts
916 with the expected length (based on the attribute type code), then
917 the Error Subcode is set to Attribute Length Error. The Data
918 field contains the erroneous attribute (type, length and
919 value). */
920 if (length != 1)
921 {
922 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
923 length);
Paul Jakma835315b2012-01-18 12:28:30 +0000924 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000925 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +0000926 args->total);
paul718e3742002-12-13 20:15:29 +0000927 }
928
929 /* Fetch origin attribute. */
930 attr->origin = stream_getc (BGP_INPUT (peer));
931
932 /* If the ORIGIN attribute has an undefined value, then the Error
933 Subcode is set to Invalid Origin Attribute. The Data field
934 contains the unrecognized attribute (type, length and value). */
935 if ((attr->origin != BGP_ORIGIN_IGP)
936 && (attr->origin != BGP_ORIGIN_EGP)
937 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
938 {
939 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
940 attr->origin);
Paul Jakma835315b2012-01-18 12:28:30 +0000941 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +0000942 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
Paul Jakma835315b2012-01-18 12:28:30 +0000943 args->total);
paul718e3742002-12-13 20:15:29 +0000944 }
945
946 /* Set oring attribute flag. */
947 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
948
949 return 0;
950}
Paul Jakmaab005292010-11-27 22:48:34 +0000951
952/* Parse AS path information. This function is wrapper of
953 aspath_parse. */
954static int
Paul Jakma835315b2012-01-18 12:28:30 +0000955bgp_attr_aspath (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +0000956{
Paul Jakma835315b2012-01-18 12:28:30 +0000957 struct attr *const attr = args->attr;
958 struct peer *const peer = args->peer;
959 const bgp_size_t length = args->length;
Paul Jakma83a9a222012-01-08 14:15:03 +0000960
Paul Jakmaab005292010-11-27 22:48:34 +0000961 /*
962 * peer with AS4 => will get 4Byte ASnums
963 * otherwise, will get 16 Bit
964 */
965 attr->aspath = aspath_parse (peer->ibuf, length,
966 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
967
968 /* In case of IBGP, length will be zero. */
969 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000970 {
Paul Jakmab881c702010-11-23 16:35:42 +0000971 zlog (peer->log, LOG_ERR,
972 "Malformed AS path from %s, length is %d",
973 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +0000974 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000975 }
Chris Hallcddb8112010-08-09 22:31:37 +0400976
Paul Jakmaab005292010-11-27 22:48:34 +0000977 /* Set aspath attribute flag. */
978 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000979
Paul Jakmab881c702010-11-23 16:35:42 +0000980 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000981}
982
Paul Jakmab881c702010-11-23 16:35:42 +0000983static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +0000984bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000985{
986 /* These checks were part of bgp_attr_aspath, but with
987 * as4 we should to check aspath things when
988 * aspath synthesizing with as4_path has already taken place.
989 * Otherwise we check ASPATH and use the synthesized thing, and that is
990 * not right.
991 * So do the checks later, i.e. here
992 */
993 struct bgp *bgp = peer->bgp;
994 struct aspath *aspath;
995
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300996 /* Confederation sanity check. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000997 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
998 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300999 {
1000 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakma835315b2012-01-18 12:28:30 +00001001 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1002 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1003 return BGP_ATTR_PARSE_ERROR;
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +03001004 }
1005
paul718e3742002-12-13 20:15:29 +00001006 /* First AS check for EBGP. */
1007 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1008 {
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001009 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00001010 && ! aspath_firstas_check (attr->aspath, peer->as))
1011 {
1012 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +04001013 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakma835315b2012-01-18 12:28:30 +00001014 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1015 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1016 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001017 }
1018 }
1019
1020 /* local-as prepend */
1021 if (peer->change_local_as &&
1022 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1023 {
1024 aspath = aspath_dup (attr->aspath);
1025 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001026 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +00001027 attr->aspath = aspath_intern (aspath);
1028 }
1029
Paul Jakmab881c702010-11-23 16:35:42 +00001030 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001031}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001032
Paul Jakmaab005292010-11-27 22:48:34 +00001033/* Parse AS4 path information. This function is another wrapper of
1034 aspath_parse. */
1035static int
Paul Jakma835315b2012-01-18 12:28:30 +00001036bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +00001037{
Paul Jakma835315b2012-01-18 12:28:30 +00001038 struct peer *const peer = args->peer;
1039 struct attr *const attr = args->attr;
1040 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001041
Paul Jakmaab005292010-11-27 22:48:34 +00001042 *as4_path = aspath_parse (peer->ibuf, length, 1);
1043
Paul Jakmab881c702010-11-23 16:35:42 +00001044 /* In case of IBGP, length will be zero. */
1045 if (!*as4_path)
1046 {
1047 zlog (peer->log, LOG_ERR,
1048 "Malformed AS4 path from %s, length is %d",
1049 peer->host, length);
Paul Jakma835315b2012-01-18 12:28:30 +00001050 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001051 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
Paul Jakma835315b2012-01-18 12:28:30 +00001052 0);
Paul Jakmab881c702010-11-23 16:35:42 +00001053 }
1054
Paul Jakmaab005292010-11-27 22:48:34 +00001055 /* Set aspath attribute flag. */
1056 if (as4_path)
1057 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1058
Paul Jakmab881c702010-11-23 16:35:42 +00001059 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001060}
1061
paul718e3742002-12-13 20:15:29 +00001062/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001063static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001064bgp_attr_nexthop (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001065{
Paul Jakma835315b2012-01-18 12:28:30 +00001066 struct peer *const peer = args->peer;
1067 struct attr *const attr = args->attr;
1068 const bgp_size_t length = args->length;
1069
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001070 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +00001071
paul718e3742002-12-13 20:15:29 +00001072 /* Check nexthop attribute length. */
1073 if (length != 4)
1074 {
1075 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1076 length);
1077
Paul Jakma835315b2012-01-18 12:28:30 +00001078 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001079 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001080 args->total);
paul718e3742002-12-13 20:15:29 +00001081 }
1082
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001083 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1084 attribute must result in a NOTIFICATION message (this is implemented below).
1085 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1086 logged locally (this is implemented somewhere else). The UPDATE message
1087 gets ignored in any of these cases. */
1088 nexthop_n = stream_get_ipv4 (peer->ibuf);
1089 nexthop_h = ntohl (nexthop_n);
1090 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1091 {
1092 char buf[INET_ADDRSTRLEN];
1093 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1094 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
Paul Jakma835315b2012-01-18 12:28:30 +00001095 return bgp_attr_malformed (args,
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001096 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Paul Jakma835315b2012-01-18 12:28:30 +00001097 args->total);
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001098 }
1099
1100 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001101 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1102
Paul Jakmab881c702010-11-23 16:35:42 +00001103 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001104}
1105
1106/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001107static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001108bgp_attr_med (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001109{
Paul Jakma835315b2012-01-18 12:28:30 +00001110 struct peer *const peer = args->peer;
1111 struct attr *const attr = args->attr;
1112 const bgp_size_t length = args->length;
1113
paul718e3742002-12-13 20:15:29 +00001114 /* Length check. */
1115 if (length != 4)
1116 {
1117 zlog (peer->log, LOG_ERR,
1118 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001119
Paul Jakma835315b2012-01-18 12:28:30 +00001120 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001121 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001122 args->total);
paul718e3742002-12-13 20:15:29 +00001123 }
1124
1125 attr->med = stream_getl (peer->ibuf);
1126
1127 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1128
Paul Jakmab881c702010-11-23 16:35:42 +00001129 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001130}
1131
1132/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001133static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001134bgp_attr_local_pref (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001135{
Paul Jakma835315b2012-01-18 12:28:30 +00001136 struct peer *const peer = args->peer;
1137 struct attr *const attr = args->attr;
1138 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001139
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001140 /* Length check. */
1141 if (length != 4)
1142 {
Paul Jakma835315b2012-01-18 12:28:30 +00001143 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
1144 length);
1145 return bgp_attr_malformed (args,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001146 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001147 args->total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001148 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001149
paul718e3742002-12-13 20:15:29 +00001150 /* If it is contained in an UPDATE message that is received from an
1151 external peer, then this attribute MUST be ignored by the
1152 receiving speaker. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00001153 if (peer->sort == BGP_PEER_EBGP)
paul718e3742002-12-13 20:15:29 +00001154 {
paul9985f832005-02-09 15:51:56 +00001155 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001156 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001157 }
1158
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001159 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001160
1161 /* Set atomic aggregate flag. */
1162 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1163
Paul Jakmab881c702010-11-23 16:35:42 +00001164 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001165}
1166
1167/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001168static int
Paul Jakma835315b2012-01-18 12:28:30 +00001169bgp_attr_atomic (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001170{
Paul Jakma835315b2012-01-18 12:28:30 +00001171 struct peer *const peer = args->peer;
1172 struct attr *const attr = args->attr;
1173 const bgp_size_t length = args->length;
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001174
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001175 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001176 if (length != 0)
1177 {
Paul Jakma835315b2012-01-18 12:28:30 +00001178 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1179 length);
1180 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001181 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001182 args->total);
paul718e3742002-12-13 20:15:29 +00001183 }
1184
1185 /* Set atomic aggregate flag. */
1186 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1187
Paul Jakmab881c702010-11-23 16:35:42 +00001188 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001189}
1190
1191/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001192static int
Paul Jakma835315b2012-01-18 12:28:30 +00001193bgp_attr_aggregator (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001194{
Paul Jakma835315b2012-01-18 12:28:30 +00001195 struct peer *const peer = args->peer;
1196 struct attr *const attr = args->attr;
1197 const bgp_size_t length = args->length;
1198
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001199 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001200 struct attr_extra *attre = bgp_attr_extra_get (attr);
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001201
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001202 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001203 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001204 wantedlen = 8;
1205
1206 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001207 {
Paul Jakma835315b2012-01-18 12:28:30 +00001208 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
1209 wantedlen, length);
1210 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001211 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001212 args->total);
paul718e3742002-12-13 20:15:29 +00001213 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001214
1215 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1216 attre->aggregator_as = stream_getl (peer->ibuf);
1217 else
1218 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001219 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001220
1221 /* Set atomic aggregate flag. */
1222 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1223
Paul Jakmab881c702010-11-23 16:35:42 +00001224 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001225}
1226
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001227/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001228static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001229bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1230 as_t *as4_aggregator_as,
1231 struct in_addr *as4_aggregator_addr)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001232{
Paul Jakma835315b2012-01-18 12:28:30 +00001233 struct peer *const peer = args->peer;
1234 struct attr *const attr = args->attr;
1235 const bgp_size_t length = args->length;
1236
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001237 if (length != 8)
1238 {
Paul Jakma835315b2012-01-18 12:28:30 +00001239 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
1240 length);
1241 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001242 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001243 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001244 }
Paul Jakma3ecab4c2012-01-17 13:31:33 +00001245
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001246 *as4_aggregator_as = stream_getl (peer->ibuf);
1247 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1248
1249 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1250
Paul Jakmab881c702010-11-23 16:35:42 +00001251 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001252}
1253
1254/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1255 */
Paul Jakmab881c702010-11-23 16:35:42 +00001256static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001257bgp_attr_munge_as4_attrs (struct peer *const peer,
1258 struct attr *const attr,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001259 struct aspath *as4_path, as_t as4_aggregator,
1260 struct in_addr *as4_aggregator_addr)
1261{
1262 int ignore_as4_path = 0;
1263 struct aspath *newpath;
1264 struct attr_extra *attre = attr->extra;
1265
Paul Jakmab881c702010-11-23 16:35:42 +00001266 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001267 {
1268 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1269 * if given.
1270 * It is worth a warning though, because the peer really
1271 * should not send them
1272 */
1273 if (BGP_DEBUG(as4, AS4))
1274 {
1275 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1276 zlog_debug ("[AS4] %s %s AS4_PATH",
1277 peer->host, "AS4 capable peer, yet it sent");
1278
1279 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1280 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1281 peer->host, "AS4 capable peer, yet it sent");
1282 }
1283
Paul Jakmab881c702010-11-23 16:35:42 +00001284 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001285 }
1286
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001287 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1288 * because that may override AS4_PATH
1289 */
1290 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1291 {
Paul Jakmab881c702010-11-23 16:35:42 +00001292 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001293 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001294 assert (attre);
1295
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001296 /* received both.
1297 * if the as_number in aggregator is not AS_TRANS,
1298 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1299 * and the Aggregator shall be taken as
1300 * info on the aggregating node, and the AS_PATH
1301 * shall be taken as the AS_PATH
1302 * otherwise
1303 * the Aggregator shall be ignored and the
1304 * AS4_AGGREGATOR shall be taken as the
1305 * Aggregating node and the AS_PATH is to be
1306 * constructed "as in all other cases"
1307 */
Paul Jakmab881c702010-11-23 16:35:42 +00001308 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001309 {
1310 /* ignore */
1311 if ( BGP_DEBUG(as4, AS4))
1312 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1313 " send AGGREGATOR != AS_TRANS and"
1314 " AS4_AGGREGATOR, so ignore"
1315 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1316 ignore_as4_path = 1;
1317 }
1318 else
1319 {
1320 /* "New_aggregator shall be taken as aggregator" */
1321 attre->aggregator_as = as4_aggregator;
1322 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1323 }
1324 }
1325 else
1326 {
1327 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1328 * That is bogus - but reading the conditions
1329 * we have to handle AS4_AGGREGATOR as if it were
1330 * AGGREGATOR in that case
1331 */
1332 if ( BGP_DEBUG(as4, AS4))
1333 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1334 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1335 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001336 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001337 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1338 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1339 }
1340 }
1341
1342 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001343 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001344 {
1345 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001346 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001347 attr->aspath = aspath_intern (newpath);
1348 }
Paul Jakmab881c702010-11-23 16:35:42 +00001349 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001350}
1351
paul718e3742002-12-13 20:15:29 +00001352/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001353static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001354bgp_attr_community (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001355{
Paul Jakma835315b2012-01-18 12:28:30 +00001356 struct peer *const peer = args->peer;
1357 struct attr *const attr = args->attr;
1358 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001359
paul718e3742002-12-13 20:15:29 +00001360 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001361 {
1362 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001363 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001364 }
Paul Jakma0c466382010-12-05 17:17:26 +00001365
1366 attr->community =
1367 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1368
1369 /* XXX: fix community_parse to use stream API and remove this */
1370 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001371
Paul Jakma0c466382010-12-05 17:17:26 +00001372 if (!attr->community)
Paul Jakma835315b2012-01-18 12:28:30 +00001373 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001374 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001375 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001376
paul718e3742002-12-13 20:15:29 +00001377 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1378
Paul Jakmab881c702010-11-23 16:35:42 +00001379 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001380}
1381
1382/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001383static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001384bgp_attr_originator_id (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001385{
Paul Jakma835315b2012-01-18 12:28:30 +00001386 struct peer *const peer = args->peer;
1387 struct attr *const attr = args->attr;
1388 const bgp_size_t length = args->length;
1389
Denis Ovsienkod595b562011-09-30 15:08:54 +04001390 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001391 if (length != 4)
1392 {
1393 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1394
Paul Jakma835315b2012-01-18 12:28:30 +00001395 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001396 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Paul Jakma835315b2012-01-18 12:28:30 +00001397 args->total);
paul718e3742002-12-13 20:15:29 +00001398 }
1399
Paul Jakmafb982c22007-05-04 20:15:47 +00001400 (bgp_attr_extra_get (attr))->originator_id.s_addr
1401 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001402
1403 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1404
Paul Jakmab881c702010-11-23 16:35:42 +00001405 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001406}
1407
1408/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001409static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001410bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001411{
Paul Jakma835315b2012-01-18 12:28:30 +00001412 struct peer *const peer = args->peer;
1413 struct attr *const attr = args->attr;
1414 const bgp_size_t length = args->length;
1415
paul718e3742002-12-13 20:15:29 +00001416 /* Check length. */
1417 if (length % 4)
1418 {
1419 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1420
Paul Jakma835315b2012-01-18 12:28:30 +00001421 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1422 args->total);
paul718e3742002-12-13 20:15:29 +00001423 }
1424
Paul Jakmafb982c22007-05-04 20:15:47 +00001425 (bgp_attr_extra_get (attr))->cluster
1426 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001427
1428 /* XXX: Fix cluster_parse to use stream API and then remove this */
1429 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001430
1431 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1432
Paul Jakmab881c702010-11-23 16:35:42 +00001433 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001434}
1435
1436/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001437int
Paul Jakma835315b2012-01-18 12:28:30 +00001438bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1439 struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001440{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001441 afi_t afi;
1442 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001443 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001444 size_t start;
paul718e3742002-12-13 20:15:29 +00001445 int ret;
1446 struct stream *s;
Paul Jakma835315b2012-01-18 12:28:30 +00001447 struct peer *const peer = args->peer;
1448 struct attr *const attr = args->attr;
1449 const bgp_size_t length = args->length;
Paul Jakmafb982c22007-05-04 20:15:47 +00001450 struct attr_extra *attre = bgp_attr_extra_get(attr);
Paul Jakma835315b2012-01-18 12:28:30 +00001451
paul718e3742002-12-13 20:15:29 +00001452 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001453 s = BGP_INPUT(peer);
1454 start = stream_get_getp(s);
1455
1456 /* safe to read statically sized header? */
1457#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001458#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001459 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001460 {
1461 zlog_info ("%s: %s sent invalid length, %lu",
1462 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001463 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001464 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001465
paul718e3742002-12-13 20:15:29 +00001466 /* Load AFI, SAFI. */
1467 afi = stream_getw (s);
1468 safi = stream_getc (s);
1469
1470 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001471 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001472
Paul Jakma03292802008-06-07 20:37:10 +00001473 if (LEN_LEFT < attre->mp_nexthop_len)
1474 {
1475 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1476 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001477 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001478 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001479
paul718e3742002-12-13 20:15:29 +00001480 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001481 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001482 {
1483 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001484 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001485 /* Probably needed for RFC 2283 */
1486 if (attr->nexthop.s_addr == 0)
1487 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001488 break;
1489 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001490 stream_getl (s); /* RD high */
1491 stream_getl (s); /* RD low */
1492 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001493 break;
1494#ifdef HAVE_IPV6
1495 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001496 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001497 break;
1498 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001499 stream_get (&attre->mp_nexthop_global, s, 16);
1500 stream_get (&attre->mp_nexthop_local, s, 16);
1501 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001502 {
1503 char buf1[INET6_ADDRSTRLEN];
1504 char buf2[INET6_ADDRSTRLEN];
1505
1506 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001507 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 +00001508 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001509 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001510 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001511 buf2, INET6_ADDRSTRLEN));
1512
Paul Jakmafb982c22007-05-04 20:15:47 +00001513 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001514 }
1515 break;
1516#endif /* HAVE_IPV6 */
1517 default:
Paul Jakma03292802008-06-07 20:37:10 +00001518 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1519 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001520 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001521 }
1522
Paul Jakma03292802008-06-07 20:37:10 +00001523 if (!LEN_LEFT)
1524 {
1525 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1526 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001527 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001528 }
paul718e3742002-12-13 20:15:29 +00001529
Paul Jakma6e4ab122007-04-10 19:36:48 +00001530 {
1531 u_char val;
1532 if ((val = stream_getc (s)))
1533 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1534 peer->host, val);
1535 }
1536
1537 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001538 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001539 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001540 {
1541 zlog_info ("%s: (%s) Failed to read NLRI",
1542 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001543 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001544 }
paul718e3742002-12-13 20:15:29 +00001545
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001546 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001547 {
1548 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001549 if (ret < 0)
1550 {
1551 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1552 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001553 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001554 }
paul718e3742002-12-13 20:15:29 +00001555 }
1556
1557 mp_update->afi = afi;
1558 mp_update->safi = safi;
1559 mp_update->nlri = stream_pnt (s);
1560 mp_update->length = nlri_len;
1561
paul9985f832005-02-09 15:51:56 +00001562 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001563
Paul Jakmab881c702010-11-23 16:35:42 +00001564 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001565#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001566}
1567
1568/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001569int
Paul Jakma835315b2012-01-18 12:28:30 +00001570bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
paul718e3742002-12-13 20:15:29 +00001571 struct bgp_nlri *mp_withdraw)
1572{
1573 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001574 afi_t afi;
1575 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001576 u_int16_t withdraw_len;
1577 int ret;
Paul Jakma835315b2012-01-18 12:28:30 +00001578 struct peer *const peer = args->peer;
1579 const bgp_size_t length = args->length;
paul718e3742002-12-13 20:15:29 +00001580
1581 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001582
1583#define BGP_MP_UNREACH_MIN_SIZE 3
1584 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001585 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001586
paul718e3742002-12-13 20:15:29 +00001587 afi = stream_getw (s);
1588 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001589
1590 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001591
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001592 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001593 {
1594 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1595 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001596 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001597 }
1598
1599 mp_withdraw->afi = afi;
1600 mp_withdraw->safi = safi;
1601 mp_withdraw->nlri = stream_pnt (s);
1602 mp_withdraw->length = withdraw_len;
1603
paul9985f832005-02-09 15:51:56 +00001604 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001605
Paul Jakmab881c702010-11-23 16:35:42 +00001606 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001607}
1608
1609/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001610static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001611bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001612{
Paul Jakma835315b2012-01-18 12:28:30 +00001613 struct peer *const peer = args->peer;
1614 struct attr *const attr = args->attr;
1615 const bgp_size_t length = args->length;
Paul Jakmab881c702010-11-23 16:35:42 +00001616
paul718e3742002-12-13 20:15:29 +00001617 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001618 {
1619 if (attr->extra)
1620 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001621 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001622 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001623 }
Paul Jakma0c466382010-12-05 17:17:26 +00001624
1625 (bgp_attr_extra_get (attr))->ecommunity =
1626 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1627 /* XXX: fix ecommunity_parse to use stream API */
1628 stream_forward_getp (peer->ibuf, length);
1629
1630 if (!attr->extra->ecommunity)
Paul Jakma835315b2012-01-18 12:28:30 +00001631 return bgp_attr_malformed (args,
1632 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1633 args->total);
Paul Jakma0c466382010-12-05 17:17:26 +00001634
paul718e3742002-12-13 20:15:29 +00001635 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1636
Paul Jakmab881c702010-11-23 16:35:42 +00001637 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001638}
1639
1640/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001641static bgp_attr_parse_ret_t
Paul Jakma835315b2012-01-18 12:28:30 +00001642bgp_attr_unknown (struct bgp_attr_parser_args *args)
paul718e3742002-12-13 20:15:29 +00001643{
Paul Jakma8794e8d2012-02-13 13:53:07 +00001644 bgp_size_t total = args->total;
paul718e3742002-12-13 20:15:29 +00001645 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001646 struct attr_extra *attre;
Paul Jakma835315b2012-01-18 12:28:30 +00001647 struct peer *const peer = args->peer;
1648 struct attr *const attr = args->attr;
1649 u_char *const startp = args->startp;
1650 const u_char type = args->type;
1651 const u_char flag = args->flags;
1652 const bgp_size_t length = args->length;
1653
paul718e3742002-12-13 20:15:29 +00001654
hassof4184462005-02-01 20:13:16 +00001655 if (BGP_DEBUG (normal, NORMAL))
1656 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1657 peer->host, type, length);
1658
paul718e3742002-12-13 20:15:29 +00001659 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001660 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001661 "Unknown attribute type %d length %d is received", type, length);
1662
1663 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001664 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001665
paul718e3742002-12-13 20:15:29 +00001666 /* If any of the mandatory well-known attributes are not recognized,
1667 then the Error Subcode is set to Unrecognized Well-known
1668 Attribute. The Data field contains the unrecognized attribute
1669 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001670 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001671 {
Paul Jakma835315b2012-01-18 12:28:30 +00001672 return bgp_attr_malformed (args,
Paul Jakmab881c702010-11-23 16:35:42 +00001673 BGP_NOTIFY_UPDATE_UNREC_ATTR,
Paul Jakma835315b2012-01-18 12:28:30 +00001674 args->total);
paul718e3742002-12-13 20:15:29 +00001675 }
1676
1677 /* Unrecognized non-transitive optional attributes must be quietly
1678 ignored and not passed along to other BGP peers. */
1679 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001680 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001681
1682 /* If a path with recognized transitive optional attribute is
1683 accepted and passed along to other BGP peers and the Partial bit
1684 in the Attribute Flags octet is set to 1 by some previous AS, it
1685 is not set back to 0 by the current AS. */
1686 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1687
1688 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001689 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001690 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001691
Paul Jakmafb982c22007-05-04 20:15:47 +00001692 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001693
1694 if (transit->val)
1695 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1696 transit->length + total);
1697 else
1698 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1699
1700 memcpy (transit->val + transit->length, startp, total);
1701 transit->length += total;
1702
Paul Jakmab881c702010-11-23 16:35:42 +00001703 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001704}
1705
1706/* Read attribute of update packet. This function is called from
1707 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001708bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001709bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1710 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1711{
1712 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001713 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001714 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001715 bgp_size_t length;
1716 u_char *startp, *endp;
1717 u_char *attr_endp;
1718 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001719 /* we need the as4_path only until we have synthesized the as_path with it */
1720 /* same goes for as4_aggregator */
1721 struct aspath *as4_path = NULL;
1722 as_t as4_aggregator = 0;
1723 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001724
1725 /* Initialize bitmap. */
1726 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1727
1728 /* End pointer of BGP attribute. */
1729 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001730
paul718e3742002-12-13 20:15:29 +00001731 /* Get attributes to the end of attribute length. */
1732 while (BGP_INPUT_PNT (peer) < endp)
1733 {
1734 /* Check remaining length check.*/
1735 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1736 {
gdtc29fdba2004-12-09 14:46:46 +00001737 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001738 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001739 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001740 peer->host,
1741 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001742
1743 bgp_notify_send (peer,
1744 BGP_NOTIFY_UPDATE_ERR,
1745 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001746 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001747 }
1748
1749 /* Fetch attribute flag and type. */
1750 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001751 /* "The lower-order four bits of the Attribute Flags octet are
1752 unused. They MUST be zero when sent and MUST be ignored when
1753 received." */
1754 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001755 type = stream_getc (BGP_INPUT (peer));
1756
Paul Jakma370b64a2007-12-22 16:49:52 +00001757 /* Check whether Extended-Length applies and is in bounds */
1758 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1759 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1760 {
1761 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001762 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001763 peer->host,
1764 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1765
1766 bgp_notify_send (peer,
1767 BGP_NOTIFY_UPDATE_ERR,
1768 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001769 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001770 }
Paul Jakma835315b2012-01-18 12:28:30 +00001771
paul718e3742002-12-13 20:15:29 +00001772 /* Check extended attribue length bit. */
1773 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1774 length = stream_getw (BGP_INPUT (peer));
1775 else
1776 length = stream_getc (BGP_INPUT (peer));
1777
1778 /* If any attribute appears more than once in the UPDATE
1779 message, then the Error Subcode is set to Malformed Attribute
1780 List. */
1781
1782 if (CHECK_BITMAP (seen, type))
1783 {
1784 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001785 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001786 peer->host, type);
1787
1788 bgp_notify_send (peer,
1789 BGP_NOTIFY_UPDATE_ERR,
1790 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001791 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001792 }
1793
1794 /* Set type to bitmap to check duplicate attribute. `type' is
1795 unsigned char so it never overflow bitmap range. */
1796
1797 SET_BITMAP (seen, type);
1798
1799 /* Overflow check. */
1800 attr_endp = BGP_INPUT_PNT (peer) + length;
1801
1802 if (attr_endp > endp)
1803 {
1804 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001805 "%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 +00001806 bgp_notify_send (peer,
1807 BGP_NOTIFY_UPDATE_ERR,
1808 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001809 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001810 }
Paul Jakma835315b2012-01-18 12:28:30 +00001811
1812 struct bgp_attr_parser_args attr_args = {
1813 .peer = peer,
1814 .length = length,
1815 .attr = attr,
1816 .type = type,
1817 .flags = flag,
1818 .startp = startp,
1819 .total = attr_endp - startp,
1820 };
1821
1822
1823 /* If any recognized attribute has Attribute Flags that conflict
1824 with the Attribute Type Code, then the Error Subcode is set to
1825 Attribute Flags Error. The Data field contains the erroneous
1826 attribute (type, length and value). */
1827 if (bgp_attr_flag_invalid (&attr_args))
Paul Jakmafa61e162012-03-25 21:31:47 +01001828 {
1829 bgp_attr_parse_ret_t ret;
1830 ret = bgp_attr_malformed (&attr_args,
1831 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1832 attr_args.total);
1833 if (ret == BGP_ATTR_PARSE_PROCEED)
1834 continue;
1835 return ret;
1836 }
paul718e3742002-12-13 20:15:29 +00001837
1838 /* OK check attribute and store it's value. */
1839 switch (type)
1840 {
1841 case BGP_ATTR_ORIGIN:
Paul Jakma835315b2012-01-18 12:28:30 +00001842 ret = bgp_attr_origin (&attr_args);
paul718e3742002-12-13 20:15:29 +00001843 break;
1844 case BGP_ATTR_AS_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001845 ret = bgp_attr_aspath (&attr_args);
paul718e3742002-12-13 20:15:29 +00001846 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001847 case BGP_ATTR_AS4_PATH:
Paul Jakma835315b2012-01-18 12:28:30 +00001848 ret = bgp_attr_as4_path (&attr_args, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001849 break;
paul718e3742002-12-13 20:15:29 +00001850 case BGP_ATTR_NEXT_HOP:
Paul Jakma835315b2012-01-18 12:28:30 +00001851 ret = bgp_attr_nexthop (&attr_args);
paul718e3742002-12-13 20:15:29 +00001852 break;
1853 case BGP_ATTR_MULTI_EXIT_DISC:
Paul Jakma835315b2012-01-18 12:28:30 +00001854 ret = bgp_attr_med (&attr_args);
paul718e3742002-12-13 20:15:29 +00001855 break;
1856 case BGP_ATTR_LOCAL_PREF:
Paul Jakma835315b2012-01-18 12:28:30 +00001857 ret = bgp_attr_local_pref (&attr_args);
paul718e3742002-12-13 20:15:29 +00001858 break;
1859 case BGP_ATTR_ATOMIC_AGGREGATE:
Paul Jakma835315b2012-01-18 12:28:30 +00001860 ret = bgp_attr_atomic (&attr_args);
paul718e3742002-12-13 20:15:29 +00001861 break;
1862 case BGP_ATTR_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001863 ret = bgp_attr_aggregator (&attr_args);
paul718e3742002-12-13 20:15:29 +00001864 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001865 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakma835315b2012-01-18 12:28:30 +00001866 ret = bgp_attr_as4_aggregator (&attr_args,
1867 &as4_aggregator,
1868 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001869 break;
paul718e3742002-12-13 20:15:29 +00001870 case BGP_ATTR_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001871 ret = bgp_attr_community (&attr_args);
paul718e3742002-12-13 20:15:29 +00001872 break;
1873 case BGP_ATTR_ORIGINATOR_ID:
Paul Jakma835315b2012-01-18 12:28:30 +00001874 ret = bgp_attr_originator_id (&attr_args);
paul718e3742002-12-13 20:15:29 +00001875 break;
1876 case BGP_ATTR_CLUSTER_LIST:
Paul Jakma835315b2012-01-18 12:28:30 +00001877 ret = bgp_attr_cluster_list (&attr_args);
paul718e3742002-12-13 20:15:29 +00001878 break;
1879 case BGP_ATTR_MP_REACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001880 ret = bgp_mp_reach_parse (&attr_args, mp_update);
paul718e3742002-12-13 20:15:29 +00001881 break;
1882 case BGP_ATTR_MP_UNREACH_NLRI:
Paul Jakma835315b2012-01-18 12:28:30 +00001883 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001884 break;
1885 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakma835315b2012-01-18 12:28:30 +00001886 ret = bgp_attr_ext_communities (&attr_args);
paul718e3742002-12-13 20:15:29 +00001887 break;
1888 default:
Paul Jakma835315b2012-01-18 12:28:30 +00001889 ret = bgp_attr_unknown (&attr_args);
paul718e3742002-12-13 20:15:29 +00001890 break;
1891 }
Paul Jakmab881c702010-11-23 16:35:42 +00001892
1893 /* If hard error occured immediately return to the caller. */
1894 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001895 {
1896 zlog (peer->log, LOG_WARNING,
1897 "%s: Attribute %s, parse error",
1898 peer->host,
1899 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001900 bgp_notify_send (peer,
1901 BGP_NOTIFY_UPDATE_ERR,
1902 BGP_NOTIFY_UPDATE_MAL_ATTR);
1903 if (as4_path)
1904 aspath_unintern (&as4_path);
1905 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001906 }
Paul Jakmab881c702010-11-23 16:35:42 +00001907 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1908 {
1909
1910 zlog (peer->log, LOG_WARNING,
1911 "%s: Attribute %s, parse error - treating as withdrawal",
1912 peer->host,
1913 LOOKUP (attr_str, type));
1914 if (as4_path)
1915 aspath_unintern (&as4_path);
1916 return ret;
1917 }
1918
paul718e3742002-12-13 20:15:29 +00001919 /* Check the fetched length. */
1920 if (BGP_INPUT_PNT (peer) != attr_endp)
1921 {
1922 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001923 "%s: BGP attribute %s, fetch error",
1924 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001925 bgp_notify_send (peer,
1926 BGP_NOTIFY_UPDATE_ERR,
1927 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001928 if (as4_path)
1929 aspath_unintern (&as4_path);
1930 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001931 }
1932 }
1933
1934 /* Check final read pointer is same as end pointer. */
1935 if (BGP_INPUT_PNT (peer) != endp)
1936 {
1937 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001938 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001939 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001940 bgp_notify_send (peer,
1941 BGP_NOTIFY_UPDATE_ERR,
1942 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001943 if (as4_path)
1944 aspath_unintern (&as4_path);
1945 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001946 }
1947
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001948 /*
1949 * At this place we can see whether we got AS4_PATH and/or
1950 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1951 * We can not do this before we've read all attributes because
1952 * the as4 handling does not say whether AS4_PATH has to be sent
1953 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1954 * in relationship to AGGREGATOR.
1955 * So, to be defensive, we are not relying on any order and read
1956 * all attributes first, including these 32bit ones, and now,
1957 * afterwards, we look what and if something is to be done for as4.
1958 */
Paul Jakma835315b2012-01-18 12:28:30 +00001959 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001960 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001961 {
1962 if (as4_path)
1963 aspath_unintern (&as4_path);
1964 return BGP_ATTR_PARSE_ERROR;
1965 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001966
1967 /* At this stage, we have done all fiddling with as4, and the
1968 * resulting info is in attr->aggregator resp. attr->aspath
1969 * so we can chuck as4_aggregator and as4_path alltogether in
1970 * order to save memory
1971 */
Paul Jakmab881c702010-11-23 16:35:42 +00001972 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001973 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001974 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001975 /* The flag that we got this is still there, but that does not
1976 * do any trouble
1977 */
1978 }
1979 /*
1980 * The "rest" of the code does nothing with as4_aggregator.
1981 * there is no memory attached specifically which is not part
1982 * of the attr.
1983 * so ignoring just means do nothing.
1984 */
1985 /*
1986 * Finally do the checks on the aspath we did not do yet
1987 * because we waited for a potentially synthesized aspath.
1988 */
Paul Jakmab881c702010-11-23 16:35:42 +00001989 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001990 {
Paul Jakma835315b2012-01-18 12:28:30 +00001991 ret = bgp_attr_aspath_check (peer, attr);
Paul Jakmab881c702010-11-23 16:35:42 +00001992 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001993 return ret;
1994 }
1995
paul718e3742002-12-13 20:15:29 +00001996 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001997 if (attr->extra && attr->extra->transit)
1998 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001999
Paul Jakmab881c702010-11-23 16:35:42 +00002000 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002001}
2002
2003/* Well-known attribute check. */
2004int
2005bgp_attr_check (struct peer *peer, struct attr *attr)
2006{
2007 u_char type = 0;
2008
2009 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2010 type = BGP_ATTR_ORIGIN;
2011
2012 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2013 type = BGP_ATTR_AS_PATH;
2014
2015 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2016 type = BGP_ATTR_NEXT_HOP;
2017
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002018 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002019 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2020 type = BGP_ATTR_LOCAL_PREF;
2021
2022 if (type)
2023 {
2024 zlog (peer->log, LOG_WARNING,
2025 "%s Missing well-known attribute %d.",
2026 peer->host, type);
2027 bgp_notify_send_with_data (peer,
2028 BGP_NOTIFY_UPDATE_ERR,
2029 BGP_NOTIFY_UPDATE_MISS_ATTR,
2030 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002031 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002032 }
Paul Jakmab881c702010-11-23 16:35:42 +00002033 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002034}
2035
2036int stream_put_prefix (struct stream *, struct prefix *);
2037
2038/* Make attribute packet. */
2039bgp_size_t
2040bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2041 struct stream *s, struct attr *attr, struct prefix *p,
2042 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002043 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002044{
paulfe69a502005-09-10 16:55:02 +00002045 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002046 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002047 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002048 int send_as4_path = 0;
2049 int send_as4_aggregator = 0;
2050 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002051
2052 if (! bgp)
2053 bgp = bgp_get_default ();
2054
2055 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002056 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002057
2058 /* Origin attribute. */
2059 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2060 stream_putc (s, BGP_ATTR_ORIGIN);
2061 stream_putc (s, 1);
2062 stream_putc (s, attr->origin);
2063
2064 /* AS path attribute. */
2065
2066 /* If remote-peer is EBGP */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002067 if (peer->sort == BGP_PEER_EBGP
paul718e3742002-12-13 20:15:29 +00002068 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002069 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002070 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002071 {
2072 aspath = aspath_dup (attr->aspath);
2073
2074 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2075 {
2076 /* Strip the confed info, and then stuff our path CONFED_ID
2077 on the front */
2078 aspath = aspath_delete_confed_seq (aspath);
2079 aspath = aspath_add_seq (aspath, bgp->confed_id);
2080 }
2081 else
2082 {
2083 aspath = aspath_add_seq (aspath, peer->local_as);
2084 if (peer->change_local_as)
2085 aspath = aspath_add_seq (aspath, peer->change_local_as);
2086 }
2087 }
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002088 else if (peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002089 {
2090 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2091 aspath = aspath_dup (attr->aspath);
2092 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2093 }
2094 else
2095 aspath = attr->aspath;
2096
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002097 /* If peer is not AS4 capable, then:
2098 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2099 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2100 * types are in it (i.e. exclude them if they are there)
2101 * AND do this only if there is at least one asnum > 65535 in the path!
2102 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2103 * all ASnums > 65535 to BGP_AS_TRANS
2104 */
paul718e3742002-12-13 20:15:29 +00002105
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002106 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2107 stream_putc (s, BGP_ATTR_AS_PATH);
2108 aspath_sizep = stream_get_endp (s);
2109 stream_putw (s, 0);
2110 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2111
2112 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2113 * in the path
2114 */
2115 if (!use32bit && aspath_has_as4 (aspath))
2116 send_as4_path = 1; /* we'll do this later, at the correct place */
2117
paul718e3742002-12-13 20:15:29 +00002118 /* Nexthop attribute. */
2119 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2120 {
2121 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2122 stream_putc (s, BGP_ATTR_NEXT_HOP);
2123 stream_putc (s, 4);
2124 if (safi == SAFI_MPLS_VPN)
2125 {
2126 if (attr->nexthop.s_addr == 0)
2127 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2128 else
2129 stream_put_ipv4 (s, attr->nexthop.s_addr);
2130 }
2131 else
2132 stream_put_ipv4 (s, attr->nexthop.s_addr);
2133 }
2134
2135 /* MED attribute. */
2136 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2137 {
2138 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2139 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2140 stream_putc (s, 4);
2141 stream_putl (s, attr->med);
2142 }
2143
2144 /* Local preference. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002145 if (peer->sort == BGP_PEER_IBGP ||
2146 peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002147 {
2148 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2149 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2150 stream_putc (s, 4);
2151 stream_putl (s, attr->local_pref);
2152 }
2153
2154 /* Atomic aggregate. */
2155 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2156 {
2157 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2158 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2159 stream_putc (s, 0);
2160 }
2161
2162 /* Aggregator. */
2163 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2164 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002165 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002166
2167 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002168 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2169 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002170
2171 if (use32bit)
2172 {
2173 /* AS4 capable peer */
2174 stream_putc (s, 8);
2175 stream_putl (s, attr->extra->aggregator_as);
2176 }
2177 else
2178 {
2179 /* 2-byte AS peer */
2180 stream_putc (s, 6);
2181
2182 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2183 if ( attr->extra->aggregator_as > 65535 )
2184 {
2185 stream_putw (s, BGP_AS_TRANS);
2186
2187 /* we have to send AS4_AGGREGATOR, too.
2188 * we'll do that later in order to send attributes in ascending
2189 * order.
2190 */
2191 send_as4_aggregator = 1;
2192 }
2193 else
2194 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2195 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002196 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002197 }
2198
2199 /* Community attribute. */
2200 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2201 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2202 {
2203 if (attr->community->size * 4 > 255)
2204 {
2205 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2206 stream_putc (s, BGP_ATTR_COMMUNITIES);
2207 stream_putw (s, attr->community->size * 4);
2208 }
2209 else
2210 {
2211 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2212 stream_putc (s, BGP_ATTR_COMMUNITIES);
2213 stream_putc (s, attr->community->size * 4);
2214 }
2215 stream_put (s, attr->community->val, attr->community->size * 4);
2216 }
2217
2218 /* Route Reflector. */
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002219 if (peer->sort == BGP_PEER_IBGP
paul718e3742002-12-13 20:15:29 +00002220 && from
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002221 && from->sort == BGP_PEER_IBGP)
paul718e3742002-12-13 20:15:29 +00002222 {
2223 /* Originator ID. */
2224 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2225 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2226 stream_putc (s, 4);
2227
2228 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002229 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002230 else
2231 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002232
2233 /* Cluster list. */
2234 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2235 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2236
Paul Jakma9eda90c2007-08-30 13:36:17 +00002237 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002238 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002239 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002240 /* If this peer configuration's parent BGP has cluster_id. */
2241 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2242 stream_put_in_addr (s, &bgp->cluster_id);
2243 else
2244 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002245 stream_put (s, attr->extra->cluster->list,
2246 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002247 }
2248 else
2249 {
2250 stream_putc (s, 4);
2251 /* If this peer configuration's parent BGP has cluster_id. */
2252 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2253 stream_put_in_addr (s, &bgp->cluster_id);
2254 else
2255 stream_put_in_addr (s, &bgp->router_id);
2256 }
2257 }
2258
2259#ifdef HAVE_IPV6
2260 /* If p is IPv6 address put it into attribute. */
2261 if (p->family == AF_INET6)
2262 {
2263 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002264 struct attr_extra *attre = attr->extra;
2265
2266 assert (attr->extra);
2267
paul718e3742002-12-13 20:15:29 +00002268 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2269 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002270 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002271 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002272 stream_putw (s, AFI_IP6); /* AFI */
2273 stream_putc (s, safi); /* SAFI */
2274
Paul Jakmafb982c22007-05-04 20:15:47 +00002275 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002276
Paul Jakmafb982c22007-05-04 20:15:47 +00002277 if (attre->mp_nexthop_len == 16)
2278 stream_put (s, &attre->mp_nexthop_global, 16);
2279 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002280 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002281 stream_put (s, &attre->mp_nexthop_global, 16);
2282 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002283 }
2284
2285 /* SNPA */
2286 stream_putc (s, 0);
2287
paul718e3742002-12-13 20:15:29 +00002288 /* Prefix write. */
2289 stream_put_prefix (s, p);
2290
2291 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002292 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002293 }
2294#endif /* HAVE_IPV6 */
2295
2296 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2297 {
2298 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002299
2300 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2301 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002302 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002303 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002304 stream_putw (s, AFI_IP); /* AFI */
2305 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2306
2307 stream_putc (s, 4);
2308 stream_put_ipv4 (s, attr->nexthop.s_addr);
2309
2310 /* SNPA */
2311 stream_putc (s, 0);
2312
paul718e3742002-12-13 20:15:29 +00002313 /* Prefix write. */
2314 stream_put_prefix (s, p);
2315
2316 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002317 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002318 }
2319
2320 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2321 {
2322 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002323
2324 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2325 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002326 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002327 stream_putc (s, 0); /* Length of this attribute. */
2328 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002329 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002330
2331 stream_putc (s, 12);
2332 stream_putl (s, 0);
2333 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002334 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002335
2336 /* SNPA */
2337 stream_putc (s, 0);
2338
paul718e3742002-12-13 20:15:29 +00002339 /* Tag, RD, Prefix write. */
2340 stream_putc (s, p->prefixlen + 88);
2341 stream_put (s, tag, 3);
2342 stream_put (s, prd->val, 8);
2343 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2344
2345 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002346 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002347 }
2348
2349 /* Extended Communities attribute. */
2350 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2351 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2352 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002353 struct attr_extra *attre = attr->extra;
2354
2355 assert (attre);
2356
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +00002357 if (peer->sort == BGP_PEER_IBGP
2358 || peer->sort == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002359 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002360 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002361 {
2362 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2363 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002364 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002365 }
2366 else
2367 {
2368 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2369 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002370 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002371 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002372 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002373 }
2374 else
2375 {
paul5228ad22004-06-04 17:58:18 +00002376 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002377 int tbit;
2378 int ecom_tr_size = 0;
2379 int i;
2380
Paul Jakmafb982c22007-05-04 20:15:47 +00002381 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002382 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002384 tbit = *pnt;
2385
2386 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2387 continue;
2388
2389 ecom_tr_size++;
2390 }
2391
2392 if (ecom_tr_size)
2393 {
2394 if (ecom_tr_size * 8 > 255)
2395 {
2396 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2397 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2398 stream_putw (s, ecom_tr_size * 8);
2399 }
2400 else
2401 {
2402 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2403 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2404 stream_putc (s, ecom_tr_size * 8);
2405 }
2406
Paul Jakmafb982c22007-05-04 20:15:47 +00002407 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002408 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002409 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002410 tbit = *pnt;
2411
2412 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2413 continue;
2414
2415 stream_put (s, pnt, 8);
2416 }
2417 }
paul718e3742002-12-13 20:15:29 +00002418 }
paul718e3742002-12-13 20:15:29 +00002419 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002420
2421 if ( send_as4_path )
2422 {
2423 /* If the peer is NOT As4 capable, AND */
2424 /* there are ASnums > 65535 in path THEN
2425 * give out AS4_PATH */
2426
2427 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2428 * path segments!
2429 * Hm, I wonder... confederation things *should* only be at
2430 * the beginning of an aspath, right? Then we should use
2431 * aspath_delete_confed_seq for this, because it is already
2432 * there! (JK)
2433 * Folks, talk to me: what is reasonable here!?
2434 */
2435 aspath = aspath_delete_confed_seq (aspath);
2436
2437 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2438 stream_putc (s, BGP_ATTR_AS4_PATH);
2439 aspath_sizep = stream_get_endp (s);
2440 stream_putw (s, 0);
2441 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2442 }
2443
2444 if (aspath != attr->aspath)
2445 aspath_free (aspath);
2446
2447 if ( send_as4_aggregator )
2448 {
2449 assert (attr->extra);
2450
2451 /* send AS4_AGGREGATOR, at this place */
2452 /* this section of code moved here in order to ensure the correct
2453 * *ascending* order of attributes
2454 */
2455 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2456 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2457 stream_putc (s, 8);
2458 stream_putl (s, attr->extra->aggregator_as);
2459 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2460 }
Paul Jakma41367172007-08-06 15:24:51 +00002461
paul718e3742002-12-13 20:15:29 +00002462 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002463 if (attr->extra && attr->extra->transit)
2464 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002465
2466 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002467 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002468}
2469
2470bgp_size_t
2471bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2472 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002473 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002474{
2475 unsigned long cp;
2476 unsigned long attrlen_pnt;
2477 bgp_size_t size;
2478
paul9985f832005-02-09 15:51:56 +00002479 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002480
2481 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2482 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2483
paul9985f832005-02-09 15:51:56 +00002484 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002485 stream_putc (s, 0); /* Length of this attribute. */
2486
2487 stream_putw (s, family2afi (p->family));
2488
2489 if (safi == SAFI_MPLS_VPN)
2490 {
2491 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002492 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002493
2494 /* prefix. */
2495 stream_putc (s, p->prefixlen + 88);
2496 stream_put (s, tag, 3);
2497 stream_put (s, prd->val, 8);
2498 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2499 }
2500 else
2501 {
2502 /* SAFI */
2503 stream_putc (s, safi);
2504
2505 /* prefix */
2506 stream_put_prefix (s, p);
2507 }
2508
2509 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002510 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002511 stream_putc_at (s, attrlen_pnt, size);
2512
paul9985f832005-02-09 15:51:56 +00002513 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002514}
2515
2516/* Initialization of attribute. */
2517void
paulfe69a502005-09-10 16:55:02 +00002518bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002519{
paul718e3742002-12-13 20:15:29 +00002520 aspath_init ();
2521 attrhash_init ();
2522 community_init ();
2523 ecommunity_init ();
2524 cluster_init ();
2525 transit_init ();
2526}
2527
Chris Caputo228da422009-07-18 05:44:03 +00002528void
2529bgp_attr_finish (void)
2530{
2531 aspath_finish ();
2532 attrhash_finish ();
2533 community_finish ();
2534 ecommunity_finish ();
2535 cluster_finish ();
2536 transit_finish ();
2537}
2538
paul718e3742002-12-13 20:15:29 +00002539/* Make attribute packet. */
2540void
paula3845922003-10-18 01:30:50 +00002541bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2542 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002543{
2544 unsigned long cp;
2545 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002546 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002547 struct aspath *aspath;
2548
2549 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002550 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002551
2552 /* Place holder of length. */
2553 stream_putw (s, 0);
2554
2555 /* Origin attribute. */
2556 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2557 stream_putc (s, BGP_ATTR_ORIGIN);
2558 stream_putc (s, 1);
2559 stream_putc (s, attr->origin);
2560
2561 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002562
2563 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2564 stream_putc (s, BGP_ATTR_AS_PATH);
2565 aspath_lenp = stream_get_endp (s);
2566 stream_putw (s, 0);
2567
2568 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002569
2570 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002571 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2572 if(prefix != NULL
2573#ifdef HAVE_IPV6
2574 && prefix->family != AF_INET6
2575#endif /* HAVE_IPV6 */
2576 )
2577 {
2578 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2579 stream_putc (s, BGP_ATTR_NEXT_HOP);
2580 stream_putc (s, 4);
2581 stream_put_ipv4 (s, attr->nexthop.s_addr);
2582 }
paul718e3742002-12-13 20:15:29 +00002583
2584 /* MED attribute. */
2585 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2586 {
2587 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2588 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2589 stream_putc (s, 4);
2590 stream_putl (s, attr->med);
2591 }
2592
2593 /* Local preference. */
2594 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2595 {
2596 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2597 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2598 stream_putc (s, 4);
2599 stream_putl (s, attr->local_pref);
2600 }
2601
2602 /* Atomic aggregate. */
2603 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2604 {
2605 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2606 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2607 stream_putc (s, 0);
2608 }
2609
2610 /* Aggregator. */
2611 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2612 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002613 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002614 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2615 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002616 stream_putc (s, 8);
2617 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002618 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002619 }
2620
2621 /* Community attribute. */
2622 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2623 {
2624 if (attr->community->size * 4 > 255)
2625 {
2626 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2627 stream_putc (s, BGP_ATTR_COMMUNITIES);
2628 stream_putw (s, attr->community->size * 4);
2629 }
2630 else
2631 {
2632 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2633 stream_putc (s, BGP_ATTR_COMMUNITIES);
2634 stream_putc (s, attr->community->size * 4);
2635 }
2636 stream_put (s, attr->community->val, attr->community->size * 4);
2637 }
2638
paula3845922003-10-18 01:30:50 +00002639#ifdef HAVE_IPV6
2640 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002641 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2642 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002643 {
2644 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002645 struct attr_extra *attre = attr->extra;
2646
paula3845922003-10-18 01:30:50 +00002647 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2648 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002649 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002650
2651 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002652 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002653 stream_putw(s, AFI_IP6); /* AFI */
2654 stream_putc(s, SAFI_UNICAST); /* SAFI */
2655
2656 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002657 stream_putc(s, attre->mp_nexthop_len);
2658 stream_put(s, &attre->mp_nexthop_global, 16);
2659 if (attre->mp_nexthop_len == 32)
2660 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002661
2662 /* SNPA */
2663 stream_putc(s, 0);
2664
2665 /* Prefix */
2666 stream_put_prefix(s, prefix);
2667
2668 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002669 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002670 }
2671#endif /* HAVE_IPV6 */
2672
paul718e3742002-12-13 20:15:29 +00002673 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002674 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002675 stream_putw_at (s, cp, len);
2676}