blob: 829b01762bc568e41b31cf5e5e211dabd5f43e0a [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"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070042static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
Denis Ovsienko452db842011-10-10 16:52:20 +040053 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
paul718e3742002-12-13 20:15:29 +000054 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000059 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
60 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
61 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
62 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000063};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070064static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
Denis Ovsienko26f5e782011-10-23 22:32:44 +040065
66static const struct message attr_flag_str[] =
67{
68 { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
69 { BGP_ATTR_FLAG_TRANS, "Transitive" },
70 { BGP_ATTR_FLAG_PARTIAL, "Partial" },
71 /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
72 { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
73};
74static const size_t attr_flag_str_max =
75 sizeof (attr_flag_str) / sizeof (attr_flag_str[0]);
paul718e3742002-12-13 20:15:29 +000076
Stephen Hemminger9bddac42009-05-15 09:59:51 -070077static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000078
paul94f2b392005-06-28 12:44:16 +000079static void *
Paul Jakma923de652007-04-29 18:25:17 +000080cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000081{
Paul Jakma923de652007-04-29 18:25:17 +000082 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000083 struct cluster_list *cluster;
84
85 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
86 cluster->length = val->length;
87
88 if (cluster->length)
89 {
90 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
91 memcpy (cluster->list, val->list, val->length);
92 }
93 else
94 cluster->list = NULL;
95
96 cluster->refcnt = 0;
97
98 return cluster;
99}
100
101/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +0000102static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +0000103cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +0000104{
105 struct cluster_list tmp;
106 struct cluster_list *cluster;
107
108 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +0000109 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000110
111 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
112 cluster->refcnt++;
113 return cluster;
114}
115
116int
117cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
118{
119 int i;
120
121 for (i = 0; i < cluster->length / 4; i++)
122 if (cluster->list[i].s_addr == originator.s_addr)
123 return 1;
124 return 0;
125}
126
paul94f2b392005-06-28 12:44:16 +0000127static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000128cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000129{
Paul Jakma923de652007-04-29 18:25:17 +0000130 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000131 unsigned int key = 0;
132 int length;
133 caddr_t pnt;
134
135 length = cluster->length;
136 pnt = (caddr_t) cluster->list;
137
138 while (length)
139 key += pnt[--length];
140
141 return key;
142}
143
paul94f2b392005-06-28 12:44:16 +0000144static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100145cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000146{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100147 const struct cluster_list * cluster1 = p1;
148 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000149
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100150 return (cluster1->length == cluster2->length &&
151 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000152}
153
paul94f2b392005-06-28 12:44:16 +0000154static void
paul718e3742002-12-13 20:15:29 +0000155cluster_free (struct cluster_list *cluster)
156{
157 if (cluster->list)
158 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
159 XFREE (MTYPE_CLUSTER, cluster);
160}
161
Chris Caputo228da422009-07-18 05:44:03 +0000162#if 0
paul94f2b392005-06-28 12:44:16 +0000163static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000164cluster_dup (struct cluster_list *cluster)
165{
166 struct cluster_list *new;
167
Stephen Hemminger393deb92008-08-18 14:13:29 -0700168 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000169 new->length = cluster->length;
170
171 if (cluster->length)
172 {
173 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
174 memcpy (new->list, cluster->list, cluster->length);
175 }
176 else
177 new->list = NULL;
178
179 return new;
180}
Chris Caputo228da422009-07-18 05:44:03 +0000181#endif
paul718e3742002-12-13 20:15:29 +0000182
paul94f2b392005-06-28 12:44:16 +0000183static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000184cluster_intern (struct cluster_list *cluster)
185{
186 struct cluster_list *find;
187
188 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
189 find->refcnt++;
190
191 return find;
192}
193
194void
195cluster_unintern (struct cluster_list *cluster)
196{
197 struct cluster_list *ret;
198
199 if (cluster->refcnt)
200 cluster->refcnt--;
201
202 if (cluster->refcnt == 0)
203 {
204 ret = hash_release (cluster_hash, cluster);
205 cluster_free (cluster);
206 }
207}
208
paul94f2b392005-06-28 12:44:16 +0000209static void
210cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000211{
212 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
213}
Chris Caputo228da422009-07-18 05:44:03 +0000214
215static void
216cluster_finish (void)
217{
218 hash_free (cluster_hash);
219 cluster_hash = NULL;
220}
paul718e3742002-12-13 20:15:29 +0000221
222/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700223static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000224
paul94f2b392005-06-28 12:44:16 +0000225static void
paul718e3742002-12-13 20:15:29 +0000226transit_free (struct transit *transit)
227{
228 if (transit->val)
229 XFREE (MTYPE_TRANSIT_VAL, transit->val);
230 XFREE (MTYPE_TRANSIT, transit);
231}
232
Paul Jakma923de652007-04-29 18:25:17 +0000233
paul94f2b392005-06-28 12:44:16 +0000234static void *
Paul Jakma923de652007-04-29 18:25:17 +0000235transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000236{
237 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000238 return p;
paul718e3742002-12-13 20:15:29 +0000239}
240
paul94f2b392005-06-28 12:44:16 +0000241static struct transit *
paul718e3742002-12-13 20:15:29 +0000242transit_intern (struct transit *transit)
243{
244 struct transit *find;
245
246 find = hash_get (transit_hash, transit, transit_hash_alloc);
247 if (find != transit)
248 transit_free (transit);
249 find->refcnt++;
250
251 return find;
252}
253
254void
255transit_unintern (struct transit *transit)
256{
257 struct transit *ret;
258
259 if (transit->refcnt)
260 transit->refcnt--;
261
262 if (transit->refcnt == 0)
263 {
264 ret = hash_release (transit_hash, transit);
265 transit_free (transit);
266 }
267}
268
paul94f2b392005-06-28 12:44:16 +0000269static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000270transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000271{
Paul Jakma923de652007-04-29 18:25:17 +0000272 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000273 unsigned int key = 0;
274 int length;
275 caddr_t pnt;
276
277 length = transit->length;
278 pnt = (caddr_t) transit->val;
279
280 while (length)
281 key += pnt[--length];
282
283 return key;
284}
285
paul94f2b392005-06-28 12:44:16 +0000286static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100287transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000288{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100289 const struct transit * transit1 = p1;
290 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000291
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100292 return (transit1->length == transit2->length &&
293 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000294}
295
paul94f2b392005-06-28 12:44:16 +0000296static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800297transit_init (void)
paul718e3742002-12-13 20:15:29 +0000298{
299 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
300}
Chris Caputo228da422009-07-18 05:44:03 +0000301
302static void
303transit_finish (void)
304{
305 hash_free (transit_hash);
306 transit_hash = NULL;
307}
paul718e3742002-12-13 20:15:29 +0000308
309/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700310static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000311
Paul Jakmafb982c22007-05-04 20:15:47 +0000312static struct attr_extra *
313bgp_attr_extra_new (void)
314{
315 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
316}
317
318void
319bgp_attr_extra_free (struct attr *attr)
320{
321 if (attr->extra)
322 {
323 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
324 attr->extra = NULL;
325 }
326}
327
328struct attr_extra *
329bgp_attr_extra_get (struct attr *attr)
330{
331 if (!attr->extra)
332 attr->extra = bgp_attr_extra_new();
333 return attr->extra;
334}
335
336/* Shallow copy of an attribute
337 * Though, not so shallow that it doesn't copy the contents
338 * of the attr_extra pointed to by 'extra'
339 */
340void
341bgp_attr_dup (struct attr *new, struct attr *orig)
342{
343 *new = *orig;
344 if (orig->extra)
345 {
346 new->extra = bgp_attr_extra_new();
347 *new->extra = *orig->extra;
348 }
349}
350
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000351unsigned long int
352attr_count (void)
353{
354 return attrhash->count;
355}
356
357unsigned long int
358attr_unknown_count (void)
359{
360 return transit_hash->count;
361}
362
paul718e3742002-12-13 20:15:29 +0000363unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000364attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000365{
Paul Jakma923de652007-04-29 18:25:17 +0000366 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000367 unsigned int key = 0;
368
369 key += attr->origin;
370 key += attr->nexthop.s_addr;
371 key += attr->med;
372 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000373
374 if (attr->extra)
375 {
376 key += attr->extra->aggregator_as;
377 key += attr->extra->aggregator_addr.s_addr;
378 key += attr->extra->weight;
379 key += attr->extra->mp_nexthop_global_in.s_addr;
380 }
381
paul718e3742002-12-13 20:15:29 +0000382 if (attr->aspath)
383 key += aspath_key_make (attr->aspath);
384 if (attr->community)
385 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000386
387 if (attr->extra)
388 {
389 if (attr->extra->ecommunity)
390 key += ecommunity_hash_make (attr->extra->ecommunity);
391 if (attr->extra->cluster)
392 key += cluster_hash_key_make (attr->extra->cluster);
393 if (attr->extra->transit)
394 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000395
396#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000397 {
398 int i;
399
400 key += attr->extra->mp_nexthop_len;
401 for (i = 0; i < 16; i++)
402 key += attr->extra->mp_nexthop_global.s6_addr[i];
403 for (i = 0; i < 16; i++)
404 key += attr->extra->mp_nexthop_local.s6_addr[i];
405 }
paul718e3742002-12-13 20:15:29 +0000406#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000407 }
paul718e3742002-12-13 20:15:29 +0000408
409 return key;
410}
411
412int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100413attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000414{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100415 const struct attr * attr1 = p1;
416 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000417
paul718e3742002-12-13 20:15:29 +0000418 if (attr1->flag == attr2->flag
419 && attr1->origin == attr2->origin
420 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000421 && attr1->aspath == attr2->aspath
422 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000423 && attr1->med == attr2->med
Paul Jakmae70e5752011-07-05 00:41:59 +0400424 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000425 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100426 const struct attr_extra *ae1 = attr1->extra;
427 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000428
429 if (ae1 && ae2
430 && ae1->aggregator_as == ae2->aggregator_as
431 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
432 && ae1->weight == ae2->weight
433#ifdef HAVE_IPV6
434 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
435 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
436 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
437#endif /* HAVE_IPV6 */
438 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
439 && ae1->ecommunity == ae2->ecommunity
440 && ae1->cluster == ae2->cluster
441 && ae1->transit == ae2->transit)
442 return 1;
443 else if (ae1 || ae2)
444 return 0;
445 /* neither attribute has extra attributes, so they're same */
446 return 1;
447 }
paul718e3742002-12-13 20:15:29 +0000448 else
449 return 0;
450}
451
paul94f2b392005-06-28 12:44:16 +0000452static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100453attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000454{
455 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
456}
457
paul94f2b392005-06-28 12:44:16 +0000458static void
Chris Caputo228da422009-07-18 05:44:03 +0000459attrhash_finish (void)
460{
461 hash_free (attrhash);
462 attrhash = NULL;
463}
464
465static void
paul718e3742002-12-13 20:15:29 +0000466attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
467{
468 struct attr *attr = backet->data;
469
470 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
471 inet_ntoa (attr->nexthop), VTY_NEWLINE);
472}
473
474void
475attr_show_all (struct vty *vty)
476{
477 hash_iterate (attrhash,
478 (void (*)(struct hash_backet *, void *))
479 attr_show_all_iterator,
480 vty);
481}
482
paul94f2b392005-06-28 12:44:16 +0000483static void *
Paul Jakma923de652007-04-29 18:25:17 +0000484bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000485{
Paul Jakma923de652007-04-29 18:25:17 +0000486 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000487 struct attr *attr;
488
489 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
490 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000491 if (val->extra)
492 {
493 attr->extra = bgp_attr_extra_new ();
494 *attr->extra = *val->extra;
495 }
paul718e3742002-12-13 20:15:29 +0000496 attr->refcnt = 0;
497 return attr;
498}
499
500/* Internet argument attribute. */
501struct attr *
502bgp_attr_intern (struct attr *attr)
503{
504 struct attr *find;
505
506 /* Intern referenced strucutre. */
507 if (attr->aspath)
508 {
509 if (! attr->aspath->refcnt)
510 attr->aspath = aspath_intern (attr->aspath);
511 else
512 attr->aspath->refcnt++;
513 }
514 if (attr->community)
515 {
516 if (! attr->community->refcnt)
517 attr->community = community_intern (attr->community);
518 else
519 attr->community->refcnt++;
520 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000521 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000522 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000523 struct attr_extra *attre = attr->extra;
524
525 if (attre->ecommunity)
526 {
527 if (! attre->ecommunity->refcnt)
528 attre->ecommunity = ecommunity_intern (attre->ecommunity);
529 else
530 attre->ecommunity->refcnt++;
531 }
532 if (attre->cluster)
533 {
534 if (! attre->cluster->refcnt)
535 attre->cluster = cluster_intern (attre->cluster);
536 else
537 attre->cluster->refcnt++;
538 }
539 if (attre->transit)
540 {
541 if (! attre->transit->refcnt)
542 attre->transit = transit_intern (attre->transit);
543 else
544 attre->transit->refcnt++;
545 }
paul718e3742002-12-13 20:15:29 +0000546 }
547
548 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
549 find->refcnt++;
550
551 return find;
552}
553
Paul Jakma03e214c2007-04-29 18:31:07 +0000554
paul718e3742002-12-13 20:15:29 +0000555/* Make network statement's attribute. */
556struct attr *
557bgp_attr_default_set (struct attr *attr, u_char origin)
558{
559 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000560 bgp_attr_extra_get (attr);
561
paul718e3742002-12-13 20:15:29 +0000562 attr->origin = origin;
563 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
564 attr->aspath = aspath_empty ();
565 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000566 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000567 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
568#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000569 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000570#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000571
paul718e3742002-12-13 20:15:29 +0000572 return attr;
573}
574
Paul Jakma03e214c2007-04-29 18:31:07 +0000575
paul718e3742002-12-13 20:15:29 +0000576/* Make network statement's attribute. */
577struct attr *
578bgp_attr_default_intern (u_char origin)
579{
580 struct attr attr;
581 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000582 struct attr_extra *attre;
583
584 memset (&attr, 0, sizeof (struct attr));
585 attre = bgp_attr_extra_get (&attr);
586
Paul Jakma03e214c2007-04-29 18:31:07 +0000587 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000588
589 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000590 bgp_attr_extra_free (&attr);
591
paul718e3742002-12-13 20:15:29 +0000592 aspath_unintern (new->aspath);
593 return new;
594}
595
596struct attr *
597bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
598 struct aspath *aspath,
599 struct community *community, int as_set)
600{
601 struct attr attr;
602 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000603 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000604
605 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000606 attre = bgp_attr_extra_get (&attr);
607
paul718e3742002-12-13 20:15:29 +0000608 /* Origin attribute. */
609 attr.origin = origin;
610 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
611
612 /* AS path attribute. */
613 if (aspath)
614 attr.aspath = aspath_intern (aspath);
615 else
616 attr.aspath = aspath_empty ();
617 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
618
619 /* Next hop attribute. */
620 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
621
622 if (community)
623 {
624 attr.community = community;
625 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
626 }
627
Paul Jakmafb982c22007-05-04 20:15:47 +0000628 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000629#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000630 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000631#endif
632 if (! as_set)
633 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
634 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
635 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000636 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000637 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000638 attre->aggregator_as = bgp->as;
639 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000640
641 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000642 bgp_attr_extra_free (&attr);
643
paul718e3742002-12-13 20:15:29 +0000644 aspath_unintern (new->aspath);
645 return new;
646}
647
648/* Free bgp attribute and aspath. */
649void
650bgp_attr_unintern (struct attr *attr)
651{
652 struct attr *ret;
653 struct aspath *aspath;
654 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000655 struct ecommunity *ecommunity = NULL;
656 struct cluster_list *cluster = NULL;
657 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000658
659 /* Decrement attribute reference. */
660 attr->refcnt--;
661 aspath = attr->aspath;
662 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000663 if (attr->extra)
664 {
665 ecommunity = attr->extra->ecommunity;
666 cluster = attr->extra->cluster;
667 transit = attr->extra->transit;
668 }
paul718e3742002-12-13 20:15:29 +0000669
670 /* If reference becomes zero then free attribute object. */
671 if (attr->refcnt == 0)
672 {
673 ret = hash_release (attrhash, attr);
674 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000675 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000676 XFREE (MTYPE_ATTR, attr);
677 }
678
679 /* aspath refcount shoud be decrement. */
680 if (aspath)
681 aspath_unintern (aspath);
682 if (community)
683 community_unintern (community);
684 if (ecommunity)
685 ecommunity_unintern (ecommunity);
686 if (cluster)
687 cluster_unintern (cluster);
688 if (transit)
689 transit_unintern (transit);
690}
691
692void
693bgp_attr_flush (struct attr *attr)
694{
695 if (attr->aspath && ! attr->aspath->refcnt)
696 aspath_free (attr->aspath);
697 if (attr->community && ! attr->community->refcnt)
698 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000699 if (attr->extra)
700 {
701 struct attr_extra *attre = attr->extra;
702 if (attre->ecommunity && ! attre->ecommunity->refcnt)
703 ecommunity_free (attre->ecommunity);
704 if (attre->cluster && ! attre->cluster->refcnt)
705 cluster_free (attre->cluster);
706 if (attre->transit && ! attre->transit->refcnt)
707 transit_free (attre->transit);
708 }
paul718e3742002-12-13 20:15:29 +0000709}
710
Denis Ovsienko26f5e782011-10-23 22:32:44 +0400711/* Find out what is wrong with the path attribute flag bits and log the error.
712 "Flag bits" here stand for Optional, Transitive and Partial, but not for
713 Extended Length. Checking O/T/P bits at once implies, that the attribute
714 being diagnosed is defined by RFC as either a "well-known" or an "optional,
715 non-transitive" attribute. */
716static void
717bgp_attr_flags_diagnose
718(
719 struct peer * peer,
720 const u_int8_t attr_code,
721 u_int8_t desired_flags, /* how RFC says it must be */
722 u_int8_t real_flags /* on wire */
723)
724{
725 u_char seen = 0, i;
726
727 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
728 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
729 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
730 if
731 (
732 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
733 CHECK_FLAG (real_flags, attr_flag_str[i].key)
734 )
735 {
736 zlog (peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
737 LOOKUP (attr_str, attr_code),
738 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
739 attr_flag_str[i].str);
740 seen = 1;
741 }
742 assert (seen);
743}
744
paul718e3742002-12-13 20:15:29 +0000745/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000746static int
paul718e3742002-12-13 20:15:29 +0000747bgp_attr_origin (struct peer *peer, bgp_size_t length,
748 struct attr *attr, u_char flag, u_char *startp)
749{
750 bgp_size_t total;
751
752 /* total is entire attribute length include Attribute Flags (1),
753 Attribute Type code (1) and Attribute length (1 or 2). */
754 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
755
756 /* If any recognized attribute has Attribute Flags that conflict
757 with the Attribute Type Code, then the Error Subcode is set to
758 Attribute Flags Error. The Data field contains the erroneous
759 attribute (type, length and value). */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400760 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400761 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +0400762 bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGIN, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400763 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
764 return -1;
765 }
paul718e3742002-12-13 20:15:29 +0000766
767 /* If any recognized attribute has Attribute Length that conflicts
768 with the expected length (based on the attribute type code), then
769 the Error Subcode is set to Attribute Length Error. The Data
770 field contains the erroneous attribute (type, length and
771 value). */
772 if (length != 1)
773 {
774 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
775 length);
776 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
777 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
778 startp, total);
779 return -1;
780 }
781
782 /* Fetch origin attribute. */
783 attr->origin = stream_getc (BGP_INPUT (peer));
784
785 /* If the ORIGIN attribute has an undefined value, then the Error
786 Subcode is set to Invalid Origin Attribute. The Data field
787 contains the unrecognized attribute (type, length and value). */
788 if ((attr->origin != BGP_ORIGIN_IGP)
789 && (attr->origin != BGP_ORIGIN_EGP)
790 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
791 {
792 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
793 attr->origin);
794
795 bgp_notify_send_with_data (peer,
796 BGP_NOTIFY_UPDATE_ERR,
797 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
798 startp, total);
799 return -1;
800 }
801
802 /* Set oring attribute flag. */
803 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
804
805 return 0;
806}
Chris Hallcddb8112010-08-09 22:31:37 +0400807/* Parse AS path information. This function is wrapper of aspath_parse.
808 *
809 * Parses AS_PATH or AS4_PATH.
810 *
811 * Returns: if valid: address of struct aspath in the hash of known aspaths,
812 * with reference count incremented.
813 * else: NULL
814 *
815 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
816 * have segments == NULL and str == zero length string (unique).
817 */
818static struct aspath *
paul718e3742002-12-13 20:15:29 +0000819bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400820 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000821{
Chris Hallcddb8112010-08-09 22:31:37 +0400822 u_char require ;
823 struct aspath *asp ;
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400824 bgp_size_t total;
825
826 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000827
Chris Hallcddb8112010-08-09 22:31:37 +0400828 /* Check the attribute flags */
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400829 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
830 {
831 zlog (peer->log, LOG_ERR,
832 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
833 bgp_notify_send_with_data (peer,
834 BGP_NOTIFY_UPDATE_ERR,
835 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
836 startp, total);
837 return NULL;
838 }
839
Chris Hallcddb8112010-08-09 22:31:37 +0400840 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
841 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000842
Chris Hallcddb8112010-08-09 22:31:37 +0400843 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000844 {
Chris Hallcddb8112010-08-09 22:31:37 +0400845 const char* path_type ;
Chris Hallcddb8112010-08-09 22:31:37 +0400846
847 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
848
849 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000850 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400851 "%s attribute flag isn't transitive %d", path_type, flag) ;
852
853 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
854 zlog (peer->log, LOG_ERR,
855 "%s attribute flag must %sbe optional %d", path_type,
Denis Ovsienko3062d2d2011-10-18 15:27:21 +0400856 CHECK_FLAG (require, BGP_ATTR_FLAG_OPTIONAL) ? "" : "not ", flag);
Chris Hallcddb8112010-08-09 22:31:37 +0400857
paul718e3742002-12-13 20:15:29 +0000858 bgp_notify_send_with_data (peer,
859 BGP_NOTIFY_UPDATE_ERR,
860 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
861 startp, total);
paul718e3742002-12-13 20:15:29 +0000862
Chris Hallcddb8112010-08-09 22:31:37 +0400863 return NULL ;
864 } ;
865
866 /* Parse the AS_PATH/AS4_PATH body.
867 *
868 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
869 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000870 */
Chris Hallcddb8112010-08-09 22:31:37 +0400871 asp = aspath_parse (peer->ibuf, length,
872 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000873
Chris Hallcddb8112010-08-09 22:31:37 +0400874 if (asp != NULL)
875 {
876 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
877 : BGP_ATTR_AS_PATH) ;
878 }
879 else
paul718e3742002-12-13 20:15:29 +0000880 {
881 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400882
883 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000884 bgp_notify_send (peer,
885 BGP_NOTIFY_UPDATE_ERR,
886 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400887 } ;
paul718e3742002-12-13 20:15:29 +0000888
Chris Hallcddb8112010-08-09 22:31:37 +0400889 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000890}
891
892static int bgp_attr_aspath_check( struct peer *peer,
893 struct attr *attr)
894{
895 /* These checks were part of bgp_attr_aspath, but with
896 * as4 we should to check aspath things when
897 * aspath synthesizing with as4_path has already taken place.
898 * Otherwise we check ASPATH and use the synthesized thing, and that is
899 * not right.
900 * So do the checks later, i.e. here
901 */
902 struct bgp *bgp = peer->bgp;
903 struct aspath *aspath;
904
paul718e3742002-12-13 20:15:29 +0000905 bgp = peer->bgp;
906
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300907 /* Confederation sanity check. */
908 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
909 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
910 {
911 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
912 bgp_notify_send (peer,
913 BGP_NOTIFY_UPDATE_ERR,
914 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
915 return -1;
916 }
917
paul718e3742002-12-13 20:15:29 +0000918 /* First AS check for EBGP. */
919 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
920 {
921 if (peer_sort (peer) == BGP_PEER_EBGP
922 && ! aspath_firstas_check (attr->aspath, peer->as))
923 {
924 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400925 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000926 bgp_notify_send (peer,
927 BGP_NOTIFY_UPDATE_ERR,
928 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
929 return -1;
930 }
931 }
932
933 /* local-as prepend */
934 if (peer->change_local_as &&
935 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
936 {
937 aspath = aspath_dup (attr->aspath);
938 aspath = aspath_add_seq (aspath, peer->change_local_as);
939 aspath_unintern (attr->aspath);
940 attr->aspath = aspath_intern (aspath);
941 }
942
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000943 return 0;
944
945}
946
paul718e3742002-12-13 20:15:29 +0000947/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000948static int
paul718e3742002-12-13 20:15:29 +0000949bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
950 struct attr *attr, u_char flag, u_char *startp)
951{
952 bgp_size_t total;
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400953 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000954
955 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
956
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400957 /* Flags check. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400958 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400959 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +0400960 bgp_attr_flags_diagnose (peer, BGP_ATTR_NEXT_HOP, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400961 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
962 return -1;
963 }
paul718e3742002-12-13 20:15:29 +0000964
965 /* Check nexthop attribute length. */
966 if (length != 4)
967 {
968 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
969 length);
970
971 bgp_notify_send_with_data (peer,
972 BGP_NOTIFY_UPDATE_ERR,
973 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
974 startp, total);
975 return -1;
976 }
977
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400978 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
979 attribute must result in a NOTIFICATION message (this is implemented below).
980 At the same time, semantically incorrect NEXT_HOP is more likely to be just
981 logged locally (this is implemented somewhere else). The UPDATE message
982 gets ignored in any of these cases. */
983 nexthop_n = stream_get_ipv4 (peer->ibuf);
984 nexthop_h = ntohl (nexthop_n);
985 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
986 {
987 char buf[INET_ADDRSTRLEN];
988 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
989 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
990 bgp_notify_send_with_data (peer,
991 BGP_NOTIFY_UPDATE_ERR,
992 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
993 startp, total);
994 return -1;
995 }
996
997 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +0000998 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
999
1000 return 0;
1001}
1002
1003/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +00001004static int
paul718e3742002-12-13 20:15:29 +00001005bgp_attr_med (struct peer *peer, bgp_size_t length,
1006 struct attr *attr, u_char flag, u_char *startp)
1007{
1008 bgp_size_t total;
1009
1010 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1011
Denis Ovsienko7d25f182011-09-20 10:54:25 +04001012 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001013 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001014 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001015 bgp_attr_flags_diagnose (peer, BGP_ATTR_MULTI_EXIT_DISC, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001016 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1017 return -1;
1018 }
Denis Ovsienko7d25f182011-09-20 10:54:25 +04001019
paul718e3742002-12-13 20:15:29 +00001020 /* Length check. */
1021 if (length != 4)
1022 {
1023 zlog (peer->log, LOG_ERR,
1024 "MED attribute length isn't four [%d]", length);
1025
1026 bgp_notify_send_with_data (peer,
1027 BGP_NOTIFY_UPDATE_ERR,
1028 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1029 startp, total);
1030 return -1;
1031 }
1032
1033 attr->med = stream_getl (peer->ibuf);
1034
1035 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1036
1037 return 0;
1038}
1039
1040/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001041static int
paul718e3742002-12-13 20:15:29 +00001042bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001043 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001044{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001045 bgp_size_t total;
1046
1047 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1048 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001049 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001050 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001051 bgp_attr_flags_diagnose (peer, BGP_ATTR_LOCAL_PREF, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001052 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1053 return -1;
1054 }
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001055 /* Length check. */
1056 if (length != 4)
1057 {
1058 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
1059 bgp_notify_send_with_data (peer,
1060 BGP_NOTIFY_UPDATE_ERR,
1061 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1062 startp, total);
1063 return -1;
1064 }
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001065
paul718e3742002-12-13 20:15:29 +00001066 /* If it is contained in an UPDATE message that is received from an
1067 external peer, then this attribute MUST be ignored by the
1068 receiving speaker. */
1069 if (peer_sort (peer) == BGP_PEER_EBGP)
1070 {
paul9985f832005-02-09 15:51:56 +00001071 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001072 return 0;
1073 }
1074
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001075 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001076
1077 /* Set atomic aggregate flag. */
1078 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1079
1080 return 0;
1081}
1082
1083/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001084static int
paul718e3742002-12-13 20:15:29 +00001085bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001086 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001087{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001088 bgp_size_t total;
1089
1090 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1091 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001092 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001093 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001094 bgp_attr_flags_diagnose (peer, BGP_ATTR_ATOMIC_AGGREGATE, BGP_ATTR_FLAG_TRANS, flag);
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001095 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1096 return -1;
1097 }
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001098
1099 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001100 if (length != 0)
1101 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001102 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
1103 bgp_notify_send_with_data (peer,
1104 BGP_NOTIFY_UPDATE_ERR,
1105 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1106 startp, total);
paul718e3742002-12-13 20:15:29 +00001107 return -1;
1108 }
1109
1110 /* Set atomic aggregate flag. */
1111 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1112
1113 return 0;
1114}
1115
1116/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001117static int
paul718e3742002-12-13 20:15:29 +00001118bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001119 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001120{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001121 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001122 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001123 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001124
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001125 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Denis Ovsienko12da1a12011-10-22 22:11:31 +04001126 /* Flags check. */
1127 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1128 {
1129 zlog (peer->log, LOG_ERR,
1130 "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag);
1131 bgp_notify_send_with_data (peer,
1132 BGP_NOTIFY_UPDATE_ERR,
1133 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1134 startp, total);
1135 return -1;
1136 }
1137 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1138 {
1139 zlog (peer->log, LOG_ERR,
1140 "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag);
1141 bgp_notify_send_with_data (peer,
1142 BGP_NOTIFY_UPDATE_ERR,
1143 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1144 startp, total);
1145 return -1;
1146 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001147 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1148 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1149 wantedlen = 8;
1150
1151 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001152 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001153 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
1154 bgp_notify_send_with_data (peer,
1155 BGP_NOTIFY_UPDATE_ERR,
1156 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1157 startp, total);
paul718e3742002-12-13 20:15:29 +00001158 return -1;
1159 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001160
1161 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1162 attre->aggregator_as = stream_getl (peer->ibuf);
1163 else
1164 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001165 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001166
1167 /* Set atomic aggregate flag. */
1168 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1169
1170 return 0;
1171}
1172
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001173/* New Aggregator attribute */
1174static int
1175bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1176 struct attr *attr, as_t *as4_aggregator_as,
1177 struct in_addr *as4_aggregator_addr)
1178{
1179 if (length != 8)
1180 {
1181 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1182
1183 bgp_notify_send (peer,
1184 BGP_NOTIFY_UPDATE_ERR,
1185 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1186 return -1;
1187 }
1188 *as4_aggregator_as = stream_getl (peer->ibuf);
1189 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1190
1191 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1192
1193 return 0;
1194}
1195
1196/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1197 */
1198static int
1199bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1200 struct aspath *as4_path, as_t as4_aggregator,
1201 struct in_addr *as4_aggregator_addr)
1202{
1203 int ignore_as4_path = 0;
1204 struct aspath *newpath;
1205 struct attr_extra *attre = attr->extra;
1206
1207 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1208 {
1209 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1210 * if given.
1211 * It is worth a warning though, because the peer really
1212 * should not send them
1213 */
1214 if (BGP_DEBUG(as4, AS4))
1215 {
1216 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1217 zlog_debug ("[AS4] %s %s AS4_PATH",
1218 peer->host, "AS4 capable peer, yet it sent");
1219
1220 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1221 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1222 peer->host, "AS4 capable peer, yet it sent");
1223 }
1224
1225 return 0;
1226 }
1227
1228 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1229 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1230 {
1231 /* Hu? This is not supposed to happen at all!
1232 * got as4_path and no aspath,
1233 * This should already
1234 * have been handled by 'well known attributes missing'
1235 * But... yeah, paranoia
1236 * Take this as a "malformed attribute"
1237 */
1238 zlog (peer->log, LOG_ERR,
1239 "%s BGP not AS4 capable peer sent AS4_PATH but"
1240 " no AS_PATH, cant do anything here", peer->host);
1241 bgp_notify_send (peer,
1242 BGP_NOTIFY_UPDATE_ERR,
1243 BGP_NOTIFY_UPDATE_MAL_ATTR);
1244 return -1;
1245 }
1246
1247 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1248 * because that may override AS4_PATH
1249 */
1250 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1251 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001252 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1253 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001254 assert (attre);
1255
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001256 /* received both.
1257 * if the as_number in aggregator is not AS_TRANS,
1258 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1259 * and the Aggregator shall be taken as
1260 * info on the aggregating node, and the AS_PATH
1261 * shall be taken as the AS_PATH
1262 * otherwise
1263 * the Aggregator shall be ignored and the
1264 * AS4_AGGREGATOR shall be taken as the
1265 * Aggregating node and the AS_PATH is to be
1266 * constructed "as in all other cases"
1267 */
1268 if ( attre->aggregator_as != BGP_AS_TRANS )
1269 {
1270 /* ignore */
1271 if ( BGP_DEBUG(as4, AS4))
1272 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1273 " send AGGREGATOR != AS_TRANS and"
1274 " AS4_AGGREGATOR, so ignore"
1275 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1276 ignore_as4_path = 1;
1277 }
1278 else
1279 {
1280 /* "New_aggregator shall be taken as aggregator" */
1281 attre->aggregator_as = as4_aggregator;
1282 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1283 }
1284 }
1285 else
1286 {
1287 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1288 * That is bogus - but reading the conditions
1289 * we have to handle AS4_AGGREGATOR as if it were
1290 * AGGREGATOR in that case
1291 */
1292 if ( BGP_DEBUG(as4, AS4))
1293 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1294 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1295 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001296 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001297 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1298 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1299 }
1300 }
1301
1302 /* need to reconcile NEW_AS_PATH and AS_PATH */
1303 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1304 {
1305 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1306 aspath_unintern (attr->aspath);
1307 attr->aspath = aspath_intern (newpath);
1308 }
1309 return 0;
1310}
1311
paul718e3742002-12-13 20:15:29 +00001312/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001313static int
paul718e3742002-12-13 20:15:29 +00001314bgp_attr_community (struct peer *peer, bgp_size_t length,
1315 struct attr *attr, u_char flag)
1316{
1317 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001318 {
1319 attr->community = NULL;
1320 return 0;
1321 }
Paul Jakmafc097162010-12-05 17:17:26 +00001322
1323 attr->community =
1324 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1325
1326 /* XXX: fix community_parse to use stream API and remove this */
1327 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001328
Paul Jakmafc097162010-12-05 17:17:26 +00001329 if (!attr->community)
1330 return -1;
1331
paul718e3742002-12-13 20:15:29 +00001332 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1333
1334 return 0;
1335}
1336
1337/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001338static int
paul718e3742002-12-13 20:15:29 +00001339bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienko5de17192011-09-30 15:08:54 +04001340 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001341{
Denis Ovsienko5de17192011-09-30 15:08:54 +04001342 bgp_size_t total;
1343
1344 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1345 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001346 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko5de17192011-09-30 15:08:54 +04001347 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001348 bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGINATOR_ID, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienko5de17192011-09-30 15:08:54 +04001349 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1350 return -1;
1351 }
1352 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001353 if (length != 4)
1354 {
1355 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1356
1357 bgp_notify_send (peer,
1358 BGP_NOTIFY_UPDATE_ERR,
1359 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1360 return -1;
1361 }
1362
Paul Jakmafb982c22007-05-04 20:15:47 +00001363 (bgp_attr_extra_get (attr))->originator_id.s_addr
1364 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001365
1366 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1367
1368 return 0;
1369}
1370
1371/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001372static int
paul718e3742002-12-13 20:15:29 +00001373bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001374 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001375{
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001376 bgp_size_t total;
1377
1378 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1379 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001380 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001381 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001382 bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001383 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1384 return -1;
1385 }
paul718e3742002-12-13 20:15:29 +00001386 /* Check length. */
1387 if (length % 4)
1388 {
1389 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1390
1391 bgp_notify_send (peer,
1392 BGP_NOTIFY_UPDATE_ERR,
1393 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1394 return -1;
1395 }
1396
Paul Jakmafb982c22007-05-04 20:15:47 +00001397 (bgp_attr_extra_get (attr))->cluster
1398 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001399
paul9985f832005-02-09 15:51:56 +00001400 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001401
1402 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1403
1404 return 0;
1405}
1406
1407/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001408int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001409bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1410 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001411{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001412 afi_t afi;
1413 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001414 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001415 size_t start;
paul718e3742002-12-13 20:15:29 +00001416 int ret;
1417 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001418 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001419 bgp_size_t total;
1420
1421 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1422 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001423 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001424 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001425 bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_REACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001426 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1427 return -1;
1428 }
paul718e3742002-12-13 20:15:29 +00001429 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001430 s = BGP_INPUT(peer);
1431 start = stream_get_getp(s);
1432
1433 /* safe to read statically sized header? */
1434#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001435#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001436 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001437 {
1438 zlog_info ("%s: %s sent invalid length, %lu",
1439 __func__, peer->host, (unsigned long)length);
1440 return -1;
1441 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001442
paul718e3742002-12-13 20:15:29 +00001443 /* Load AFI, SAFI. */
1444 afi = stream_getw (s);
1445 safi = stream_getc (s);
1446
1447 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001448 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001449
Paul Jakma03292802008-06-07 20:37:10 +00001450 if (LEN_LEFT < attre->mp_nexthop_len)
1451 {
1452 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1453 __func__, peer->host, attre->mp_nexthop_len);
1454 return -1;
1455 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001456
paul718e3742002-12-13 20:15:29 +00001457 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001458 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001459 {
1460 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001461 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001462 /* Probably needed for RFC 2283 */
1463 if (attr->nexthop.s_addr == 0)
1464 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001465 break;
1466 case 12:
1467 {
1468 u_int32_t rd_high;
1469 u_int32_t rd_low;
1470
1471 rd_high = stream_getl (s);
1472 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001473 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001474 }
1475 break;
1476#ifdef HAVE_IPV6
1477 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001478 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001479 break;
1480 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001481 stream_get (&attre->mp_nexthop_global, s, 16);
1482 stream_get (&attre->mp_nexthop_local, s, 16);
1483 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001484 {
1485 char buf1[INET6_ADDRSTRLEN];
1486 char buf2[INET6_ADDRSTRLEN];
1487
1488 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001489 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 +00001490 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001491 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001492 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001493 buf2, INET6_ADDRSTRLEN));
1494
Paul Jakmafb982c22007-05-04 20:15:47 +00001495 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001496 }
1497 break;
1498#endif /* HAVE_IPV6 */
1499 default:
Paul Jakma03292802008-06-07 20:37:10 +00001500 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1501 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001502 return -1;
paul718e3742002-12-13 20:15:29 +00001503 }
1504
Paul Jakma03292802008-06-07 20:37:10 +00001505 if (!LEN_LEFT)
1506 {
1507 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1508 __func__, peer->host);
1509 return -1;
1510 }
paul718e3742002-12-13 20:15:29 +00001511
Paul Jakma6e4ab122007-04-10 19:36:48 +00001512 {
1513 u_char val;
1514 if ((val = stream_getc (s)))
1515 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1516 peer->host, val);
1517 }
1518
1519 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001520 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001521 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001522 {
1523 zlog_info ("%s: (%s) Failed to read NLRI",
1524 __func__, peer->host);
1525 return -1;
1526 }
paul718e3742002-12-13 20:15:29 +00001527
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001528 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001529 {
1530 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001531 if (ret < 0)
1532 {
1533 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1534 __func__, peer->host);
1535 return -1;
1536 }
paul718e3742002-12-13 20:15:29 +00001537 }
1538
1539 mp_update->afi = afi;
1540 mp_update->safi = safi;
1541 mp_update->nlri = stream_pnt (s);
1542 mp_update->length = nlri_len;
1543
paul9985f832005-02-09 15:51:56 +00001544 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001545
1546 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001547#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001548}
1549
1550/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001551int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001552bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1553 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001554 struct bgp_nlri *mp_withdraw)
1555{
1556 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001557 afi_t afi;
1558 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001559 u_int16_t withdraw_len;
1560 int ret;
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001561 bgp_size_t total;
1562
1563 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1564 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001565 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001566 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001567 bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_UNREACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001568 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1569 return -1;
1570 }
paul718e3742002-12-13 20:15:29 +00001571
1572 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001573
1574#define BGP_MP_UNREACH_MIN_SIZE 3
1575 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1576 return -1;
1577
paul718e3742002-12-13 20:15:29 +00001578 afi = stream_getw (s);
1579 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001580
1581 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001582
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001583 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001584 {
1585 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1586 if (ret < 0)
1587 return -1;
1588 }
1589
1590 mp_withdraw->afi = afi;
1591 mp_withdraw->safi = safi;
1592 mp_withdraw->nlri = stream_pnt (s);
1593 mp_withdraw->length = withdraw_len;
1594
paul9985f832005-02-09 15:51:56 +00001595 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001596
1597 return 0;
1598}
1599
1600/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001601static int
paul718e3742002-12-13 20:15:29 +00001602bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1603 struct attr *attr, u_char flag)
1604{
1605 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001606 {
1607 if (attr->extra)
1608 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001609 /* Empty extcomm doesn't seem to be invalid per se */
1610 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001611 }
Paul Jakmafc097162010-12-05 17:17:26 +00001612
1613 (bgp_attr_extra_get (attr))->ecommunity =
1614 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1615 /* XXX: fix ecommunity_parse to use stream API */
1616 stream_forward_getp (peer->ibuf, length);
1617
1618 if (!attr->extra->ecommunity)
1619 return -1;
1620
paul718e3742002-12-13 20:15:29 +00001621 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1622
1623 return 0;
1624}
1625
1626/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001627static int
paul718e3742002-12-13 20:15:29 +00001628bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1629 u_char type, bgp_size_t length, u_char *startp)
1630{
1631 bgp_size_t total;
1632 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001633 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001634
hassof4184462005-02-01 20:13:16 +00001635 if (BGP_DEBUG (normal, NORMAL))
1636 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1637 peer->host, type, length);
1638
paul718e3742002-12-13 20:15:29 +00001639 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001640 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001641 "Unknown attribute type %d length %d is received", type, length);
1642
1643 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001644 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001645
1646 /* Adjest total length to include type and length. */
1647 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1648
1649 /* If any of the mandatory well-known attributes are not recognized,
1650 then the Error Subcode is set to Unrecognized Well-known
1651 Attribute. The Data field contains the unrecognized attribute
1652 (type, length and value). */
1653 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1654 {
1655 /* Adjust startp to do not include flag value. */
1656 bgp_notify_send_with_data (peer,
1657 BGP_NOTIFY_UPDATE_ERR,
1658 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1659 startp, total);
1660 return -1;
1661 }
1662
1663 /* Unrecognized non-transitive optional attributes must be quietly
1664 ignored and not passed along to other BGP peers. */
1665 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1666 return 0;
1667
1668 /* If a path with recognized transitive optional attribute is
1669 accepted and passed along to other BGP peers and the Partial bit
1670 in the Attribute Flags octet is set to 1 by some previous AS, it
1671 is not set back to 0 by the current AS. */
1672 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1673
1674 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001675 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001676 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001677
Paul Jakmafb982c22007-05-04 20:15:47 +00001678 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001679
1680 if (transit->val)
1681 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1682 transit->length + total);
1683 else
1684 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1685
1686 memcpy (transit->val + transit->length, startp, total);
1687 transit->length += total;
1688
1689 return 0;
1690}
1691
1692/* Read attribute of update packet. This function is called from
1693 bgp_update() in bgpd.c. */
1694int
1695bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1696 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1697{
1698 int ret;
1699 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001700 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001701 bgp_size_t length;
1702 u_char *startp, *endp;
1703 u_char *attr_endp;
1704 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001705 /* we need the as4_path only until we have synthesized the as_path with it */
1706 /* same goes for as4_aggregator */
1707 struct aspath *as4_path = NULL;
1708 as_t as4_aggregator = 0;
1709 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001710
1711 /* Initialize bitmap. */
1712 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1713
1714 /* End pointer of BGP attribute. */
1715 endp = BGP_INPUT_PNT (peer) + size;
1716
1717 /* Get attributes to the end of attribute length. */
1718 while (BGP_INPUT_PNT (peer) < endp)
1719 {
1720 /* Check remaining length check.*/
1721 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1722 {
gdtc29fdba2004-12-09 14:46:46 +00001723 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001724 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001725 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001726 peer->host,
1727 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001728
1729 bgp_notify_send (peer,
1730 BGP_NOTIFY_UPDATE_ERR,
1731 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1732 return -1;
1733 }
1734
1735 /* Fetch attribute flag and type. */
1736 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001737 /* "The lower-order four bits of the Attribute Flags octet are
1738 unused. They MUST be zero when sent and MUST be ignored when
1739 received." */
1740 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001741 type = stream_getc (BGP_INPUT (peer));
1742
Paul Jakma370b64a2007-12-22 16:49:52 +00001743 /* Check whether Extended-Length applies and is in bounds */
1744 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1745 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1746 {
1747 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001748 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001749 peer->host,
1750 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1751
1752 bgp_notify_send (peer,
1753 BGP_NOTIFY_UPDATE_ERR,
1754 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1755 return -1;
1756 }
1757
paul718e3742002-12-13 20:15:29 +00001758 /* Check extended attribue length bit. */
1759 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1760 length = stream_getw (BGP_INPUT (peer));
1761 else
1762 length = stream_getc (BGP_INPUT (peer));
1763
1764 /* If any attribute appears more than once in the UPDATE
1765 message, then the Error Subcode is set to Malformed Attribute
1766 List. */
1767
1768 if (CHECK_BITMAP (seen, type))
1769 {
1770 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001771 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001772 peer->host, type);
1773
1774 bgp_notify_send (peer,
1775 BGP_NOTIFY_UPDATE_ERR,
1776 BGP_NOTIFY_UPDATE_MAL_ATTR);
1777 return -1;
1778 }
1779
1780 /* Set type to bitmap to check duplicate attribute. `type' is
1781 unsigned char so it never overflow bitmap range. */
1782
1783 SET_BITMAP (seen, type);
1784
1785 /* Overflow check. */
1786 attr_endp = BGP_INPUT_PNT (peer) + length;
1787
1788 if (attr_endp > endp)
1789 {
1790 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001791 "%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 +00001792 bgp_notify_send (peer,
1793 BGP_NOTIFY_UPDATE_ERR,
1794 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1795 return -1;
1796 }
1797
1798 /* OK check attribute and store it's value. */
1799 switch (type)
1800 {
1801 case BGP_ATTR_ORIGIN:
1802 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1803 break;
1804 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001805 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1806 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001807 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001808 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001809 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1810 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001811 break;
paul718e3742002-12-13 20:15:29 +00001812 case BGP_ATTR_NEXT_HOP:
1813 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1814 break;
1815 case BGP_ATTR_MULTI_EXIT_DISC:
1816 ret = bgp_attr_med (peer, length, attr, flag, startp);
1817 break;
1818 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001819 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001820 break;
1821 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001822 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001823 break;
1824 case BGP_ATTR_AGGREGATOR:
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001825 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001826 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001827 case BGP_ATTR_AS4_AGGREGATOR:
1828 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1829 break;
paul718e3742002-12-13 20:15:29 +00001830 case BGP_ATTR_COMMUNITIES:
1831 ret = bgp_attr_community (peer, length, attr, flag);
1832 break;
1833 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienko5de17192011-09-30 15:08:54 +04001834 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001835 break;
1836 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001837 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001838 break;
1839 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001840 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001841 break;
1842 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001843 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001844 break;
1845 case BGP_ATTR_EXT_COMMUNITIES:
1846 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1847 break;
1848 default:
1849 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1850 break;
1851 }
1852
1853 /* If error occured immediately return to the caller. */
1854 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001855 {
1856 zlog (peer->log, LOG_WARNING,
1857 "%s: Attribute %s, parse error",
1858 peer->host,
1859 LOOKUP (attr_str, type));
1860 bgp_notify_send (peer,
1861 BGP_NOTIFY_UPDATE_ERR,
1862 BGP_NOTIFY_UPDATE_MAL_ATTR);
1863 return ret;
1864 }
paul718e3742002-12-13 20:15:29 +00001865
1866 /* Check the fetched length. */
1867 if (BGP_INPUT_PNT (peer) != attr_endp)
1868 {
1869 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001870 "%s: BGP attribute %s, fetch error",
1871 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001872 bgp_notify_send (peer,
1873 BGP_NOTIFY_UPDATE_ERR,
1874 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1875 return -1;
1876 }
1877 }
1878
1879 /* Check final read pointer is same as end pointer. */
1880 if (BGP_INPUT_PNT (peer) != endp)
1881 {
1882 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001883 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001884 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001885 bgp_notify_send (peer,
1886 BGP_NOTIFY_UPDATE_ERR,
1887 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1888 return -1;
1889 }
1890
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001891 /*
1892 * At this place we can see whether we got AS4_PATH and/or
1893 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1894 * We can not do this before we've read all attributes because
1895 * the as4 handling does not say whether AS4_PATH has to be sent
1896 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1897 * in relationship to AGGREGATOR.
1898 * So, to be defensive, we are not relying on any order and read
1899 * all attributes first, including these 32bit ones, and now,
1900 * afterwards, we look what and if something is to be done for as4.
1901 */
1902 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1903 as4_aggregator, &as4_aggregator_addr))
1904 return -1;
1905
1906 /* At this stage, we have done all fiddling with as4, and the
1907 * resulting info is in attr->aggregator resp. attr->aspath
1908 * so we can chuck as4_aggregator and as4_path alltogether in
1909 * order to save memory
1910 */
1911 if ( as4_path )
1912 {
1913 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1914 as4_path = NULL;
1915 /* The flag that we got this is still there, but that does not
1916 * do any trouble
1917 */
1918 }
1919 /*
1920 * The "rest" of the code does nothing with as4_aggregator.
1921 * there is no memory attached specifically which is not part
1922 * of the attr.
1923 * so ignoring just means do nothing.
1924 */
1925 /*
1926 * Finally do the checks on the aspath we did not do yet
1927 * because we waited for a potentially synthesized aspath.
1928 */
1929 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1930 {
1931 ret = bgp_attr_aspath_check( peer, attr );
1932 if ( ret < 0 )
1933 return ret;
1934 }
1935
paul718e3742002-12-13 20:15:29 +00001936 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001937 if (attr->extra && attr->extra->transit)
1938 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001939
1940 return 0;
1941}
1942
1943/* Well-known attribute check. */
1944int
1945bgp_attr_check (struct peer *peer, struct attr *attr)
1946{
1947 u_char type = 0;
1948
1949 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1950 type = BGP_ATTR_ORIGIN;
1951
1952 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1953 type = BGP_ATTR_AS_PATH;
1954
1955 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1956 type = BGP_ATTR_NEXT_HOP;
1957
1958 if (peer_sort (peer) == BGP_PEER_IBGP
1959 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1960 type = BGP_ATTR_LOCAL_PREF;
1961
1962 if (type)
1963 {
1964 zlog (peer->log, LOG_WARNING,
1965 "%s Missing well-known attribute %d.",
1966 peer->host, type);
1967 bgp_notify_send_with_data (peer,
1968 BGP_NOTIFY_UPDATE_ERR,
1969 BGP_NOTIFY_UPDATE_MISS_ATTR,
1970 &type, 1);
1971 return -1;
1972 }
1973 return 0;
1974}
1975
1976int stream_put_prefix (struct stream *, struct prefix *);
1977
1978/* Make attribute packet. */
1979bgp_size_t
1980bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1981 struct stream *s, struct attr *attr, struct prefix *p,
1982 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001983 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001984{
paulfe69a502005-09-10 16:55:02 +00001985 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001986 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001987 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001988 int send_as4_path = 0;
1989 int send_as4_aggregator = 0;
1990 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001991
1992 if (! bgp)
1993 bgp = bgp_get_default ();
1994
1995 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001996 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001997
1998 /* Origin attribute. */
1999 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2000 stream_putc (s, BGP_ATTR_ORIGIN);
2001 stream_putc (s, 1);
2002 stream_putc (s, attr->origin);
2003
2004 /* AS path attribute. */
2005
2006 /* If remote-peer is EBGP */
2007 if (peer_sort (peer) == BGP_PEER_EBGP
2008 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002009 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002010 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002011 {
2012 aspath = aspath_dup (attr->aspath);
2013
2014 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2015 {
2016 /* Strip the confed info, and then stuff our path CONFED_ID
2017 on the front */
2018 aspath = aspath_delete_confed_seq (aspath);
2019 aspath = aspath_add_seq (aspath, bgp->confed_id);
2020 }
2021 else
2022 {
2023 aspath = aspath_add_seq (aspath, peer->local_as);
2024 if (peer->change_local_as)
2025 aspath = aspath_add_seq (aspath, peer->change_local_as);
2026 }
2027 }
2028 else if (peer_sort (peer) == BGP_PEER_CONFED)
2029 {
2030 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2031 aspath = aspath_dup (attr->aspath);
2032 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2033 }
2034 else
2035 aspath = attr->aspath;
2036
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002037 /* If peer is not AS4 capable, then:
2038 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2039 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2040 * types are in it (i.e. exclude them if they are there)
2041 * AND do this only if there is at least one asnum > 65535 in the path!
2042 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2043 * all ASnums > 65535 to BGP_AS_TRANS
2044 */
paul718e3742002-12-13 20:15:29 +00002045
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002046 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2047 stream_putc (s, BGP_ATTR_AS_PATH);
2048 aspath_sizep = stream_get_endp (s);
2049 stream_putw (s, 0);
2050 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2051
2052 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2053 * in the path
2054 */
2055 if (!use32bit && aspath_has_as4 (aspath))
2056 send_as4_path = 1; /* we'll do this later, at the correct place */
2057
paul718e3742002-12-13 20:15:29 +00002058 /* Nexthop attribute. */
2059 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2060 {
2061 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2062 stream_putc (s, BGP_ATTR_NEXT_HOP);
2063 stream_putc (s, 4);
2064 if (safi == SAFI_MPLS_VPN)
2065 {
2066 if (attr->nexthop.s_addr == 0)
2067 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2068 else
2069 stream_put_ipv4 (s, attr->nexthop.s_addr);
2070 }
2071 else
2072 stream_put_ipv4 (s, attr->nexthop.s_addr);
2073 }
2074
2075 /* MED attribute. */
2076 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2077 {
2078 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2079 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2080 stream_putc (s, 4);
2081 stream_putl (s, attr->med);
2082 }
2083
2084 /* Local preference. */
2085 if (peer_sort (peer) == BGP_PEER_IBGP ||
2086 peer_sort (peer) == BGP_PEER_CONFED)
2087 {
2088 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2089 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2090 stream_putc (s, 4);
2091 stream_putl (s, attr->local_pref);
2092 }
2093
2094 /* Atomic aggregate. */
2095 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2096 {
2097 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2098 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2099 stream_putc (s, 0);
2100 }
2101
2102 /* Aggregator. */
2103 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2104 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002105 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002106
2107 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002108 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2109 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002110
2111 if (use32bit)
2112 {
2113 /* AS4 capable peer */
2114 stream_putc (s, 8);
2115 stream_putl (s, attr->extra->aggregator_as);
2116 }
2117 else
2118 {
2119 /* 2-byte AS peer */
2120 stream_putc (s, 6);
2121
2122 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2123 if ( attr->extra->aggregator_as > 65535 )
2124 {
2125 stream_putw (s, BGP_AS_TRANS);
2126
2127 /* we have to send AS4_AGGREGATOR, too.
2128 * we'll do that later in order to send attributes in ascending
2129 * order.
2130 */
2131 send_as4_aggregator = 1;
2132 }
2133 else
2134 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2135 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002136 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002137 }
2138
2139 /* Community attribute. */
2140 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2141 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2142 {
2143 if (attr->community->size * 4 > 255)
2144 {
2145 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2146 stream_putc (s, BGP_ATTR_COMMUNITIES);
2147 stream_putw (s, attr->community->size * 4);
2148 }
2149 else
2150 {
2151 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2152 stream_putc (s, BGP_ATTR_COMMUNITIES);
2153 stream_putc (s, attr->community->size * 4);
2154 }
2155 stream_put (s, attr->community->val, attr->community->size * 4);
2156 }
2157
2158 /* Route Reflector. */
2159 if (peer_sort (peer) == BGP_PEER_IBGP
2160 && from
2161 && peer_sort (from) == BGP_PEER_IBGP)
2162 {
2163 /* Originator ID. */
2164 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2165 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2166 stream_putc (s, 4);
2167
2168 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002169 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002170 else
2171 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002172
2173 /* Cluster list. */
2174 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2175 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2176
Paul Jakma9eda90c2007-08-30 13:36:17 +00002177 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002178 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002179 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002180 /* If this peer configuration's parent BGP has cluster_id. */
2181 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2182 stream_put_in_addr (s, &bgp->cluster_id);
2183 else
2184 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002185 stream_put (s, attr->extra->cluster->list,
2186 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002187 }
2188 else
2189 {
2190 stream_putc (s, 4);
2191 /* If this peer configuration's parent BGP has cluster_id. */
2192 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2193 stream_put_in_addr (s, &bgp->cluster_id);
2194 else
2195 stream_put_in_addr (s, &bgp->router_id);
2196 }
2197 }
2198
2199#ifdef HAVE_IPV6
2200 /* If p is IPv6 address put it into attribute. */
2201 if (p->family == AF_INET6)
2202 {
2203 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002204 struct attr_extra *attre = attr->extra;
2205
2206 assert (attr->extra);
2207
paul718e3742002-12-13 20:15:29 +00002208 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2209 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002210 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002211 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002212 stream_putw (s, AFI_IP6); /* AFI */
2213 stream_putc (s, safi); /* SAFI */
2214
Paul Jakmafb982c22007-05-04 20:15:47 +00002215 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002216
Paul Jakmafb982c22007-05-04 20:15:47 +00002217 if (attre->mp_nexthop_len == 16)
2218 stream_put (s, &attre->mp_nexthop_global, 16);
2219 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002220 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002221 stream_put (s, &attre->mp_nexthop_global, 16);
2222 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002223 }
2224
2225 /* SNPA */
2226 stream_putc (s, 0);
2227
paul718e3742002-12-13 20:15:29 +00002228 /* Prefix write. */
2229 stream_put_prefix (s, p);
2230
2231 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002232 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002233 }
2234#endif /* HAVE_IPV6 */
2235
2236 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2237 {
2238 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002239
2240 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2241 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002242 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002243 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002244 stream_putw (s, AFI_IP); /* AFI */
2245 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2246
2247 stream_putc (s, 4);
2248 stream_put_ipv4 (s, attr->nexthop.s_addr);
2249
2250 /* SNPA */
2251 stream_putc (s, 0);
2252
paul718e3742002-12-13 20:15:29 +00002253 /* Prefix write. */
2254 stream_put_prefix (s, p);
2255
2256 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002257 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002258 }
2259
2260 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2261 {
2262 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002263
2264 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2265 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002266 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002267 stream_putc (s, 0); /* Length of this attribute. */
2268 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002269 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002270
2271 stream_putc (s, 12);
2272 stream_putl (s, 0);
2273 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002275
2276 /* SNPA */
2277 stream_putc (s, 0);
2278
paul718e3742002-12-13 20:15:29 +00002279 /* Tag, RD, Prefix write. */
2280 stream_putc (s, p->prefixlen + 88);
2281 stream_put (s, tag, 3);
2282 stream_put (s, prd->val, 8);
2283 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2284
2285 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002286 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002287 }
2288
2289 /* Extended Communities attribute. */
2290 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2291 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2292 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002293 struct attr_extra *attre = attr->extra;
2294
2295 assert (attre);
2296
2297 if (peer_sort (peer) == BGP_PEER_IBGP
2298 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002299 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002300 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002301 {
2302 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2303 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002304 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002305 }
2306 else
2307 {
2308 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2309 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002310 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002311 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002312 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002313 }
2314 else
2315 {
paul5228ad22004-06-04 17:58:18 +00002316 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002317 int tbit;
2318 int ecom_tr_size = 0;
2319 int i;
2320
Paul Jakmafb982c22007-05-04 20:15:47 +00002321 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002322 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002323 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002324 tbit = *pnt;
2325
2326 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2327 continue;
2328
2329 ecom_tr_size++;
2330 }
2331
2332 if (ecom_tr_size)
2333 {
2334 if (ecom_tr_size * 8 > 255)
2335 {
2336 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2337 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2338 stream_putw (s, ecom_tr_size * 8);
2339 }
2340 else
2341 {
2342 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2343 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2344 stream_putc (s, ecom_tr_size * 8);
2345 }
2346
Paul Jakmafb982c22007-05-04 20:15:47 +00002347 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002348 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002349 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002350 tbit = *pnt;
2351
2352 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2353 continue;
2354
2355 stream_put (s, pnt, 8);
2356 }
2357 }
paul718e3742002-12-13 20:15:29 +00002358 }
paul718e3742002-12-13 20:15:29 +00002359 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002360
2361 if ( send_as4_path )
2362 {
2363 /* If the peer is NOT As4 capable, AND */
2364 /* there are ASnums > 65535 in path THEN
2365 * give out AS4_PATH */
2366
2367 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2368 * path segments!
2369 * Hm, I wonder... confederation things *should* only be at
2370 * the beginning of an aspath, right? Then we should use
2371 * aspath_delete_confed_seq for this, because it is already
2372 * there! (JK)
2373 * Folks, talk to me: what is reasonable here!?
2374 */
2375 aspath = aspath_delete_confed_seq (aspath);
2376
2377 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2378 stream_putc (s, BGP_ATTR_AS4_PATH);
2379 aspath_sizep = stream_get_endp (s);
2380 stream_putw (s, 0);
2381 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2382 }
2383
2384 if (aspath != attr->aspath)
2385 aspath_free (aspath);
2386
2387 if ( send_as4_aggregator )
2388 {
2389 assert (attr->extra);
2390
2391 /* send AS4_AGGREGATOR, at this place */
2392 /* this section of code moved here in order to ensure the correct
2393 * *ascending* order of attributes
2394 */
2395 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2396 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2397 stream_putc (s, 8);
2398 stream_putl (s, attr->extra->aggregator_as);
2399 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2400 }
Paul Jakma41367172007-08-06 15:24:51 +00002401
paul718e3742002-12-13 20:15:29 +00002402 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002403 if (attr->extra && attr->extra->transit)
2404 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002405
2406 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002407 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002408}
2409
2410bgp_size_t
2411bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2412 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002413 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002414{
2415 unsigned long cp;
2416 unsigned long attrlen_pnt;
2417 bgp_size_t size;
2418
paul9985f832005-02-09 15:51:56 +00002419 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002420
2421 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2422 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2423
paul9985f832005-02-09 15:51:56 +00002424 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002425 stream_putc (s, 0); /* Length of this attribute. */
2426
2427 stream_putw (s, family2afi (p->family));
2428
2429 if (safi == SAFI_MPLS_VPN)
2430 {
2431 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002432 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002433
2434 /* prefix. */
2435 stream_putc (s, p->prefixlen + 88);
2436 stream_put (s, tag, 3);
2437 stream_put (s, prd->val, 8);
2438 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2439 }
2440 else
2441 {
2442 /* SAFI */
2443 stream_putc (s, safi);
2444
2445 /* prefix */
2446 stream_put_prefix (s, p);
2447 }
2448
2449 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002450 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002451 stream_putc_at (s, attrlen_pnt, size);
2452
paul9985f832005-02-09 15:51:56 +00002453 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002454}
2455
2456/* Initialization of attribute. */
2457void
paulfe69a502005-09-10 16:55:02 +00002458bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002459{
paul718e3742002-12-13 20:15:29 +00002460 aspath_init ();
2461 attrhash_init ();
2462 community_init ();
2463 ecommunity_init ();
2464 cluster_init ();
2465 transit_init ();
2466}
2467
Chris Caputo228da422009-07-18 05:44:03 +00002468void
2469bgp_attr_finish (void)
2470{
2471 aspath_finish ();
2472 attrhash_finish ();
2473 community_finish ();
2474 ecommunity_finish ();
2475 cluster_finish ();
2476 transit_finish ();
2477}
2478
paul718e3742002-12-13 20:15:29 +00002479/* Make attribute packet. */
2480void
paula3845922003-10-18 01:30:50 +00002481bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2482 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002483{
2484 unsigned long cp;
2485 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002486 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002487 struct aspath *aspath;
2488
2489 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002490 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002491
2492 /* Place holder of length. */
2493 stream_putw (s, 0);
2494
2495 /* Origin attribute. */
2496 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2497 stream_putc (s, BGP_ATTR_ORIGIN);
2498 stream_putc (s, 1);
2499 stream_putc (s, attr->origin);
2500
2501 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002502
2503 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2504 stream_putc (s, BGP_ATTR_AS_PATH);
2505 aspath_lenp = stream_get_endp (s);
2506 stream_putw (s, 0);
2507
2508 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002509
2510 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002511 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2512 if(prefix != NULL
2513#ifdef HAVE_IPV6
2514 && prefix->family != AF_INET6
2515#endif /* HAVE_IPV6 */
2516 )
2517 {
2518 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2519 stream_putc (s, BGP_ATTR_NEXT_HOP);
2520 stream_putc (s, 4);
2521 stream_put_ipv4 (s, attr->nexthop.s_addr);
2522 }
paul718e3742002-12-13 20:15:29 +00002523
2524 /* MED attribute. */
2525 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2526 {
2527 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2528 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2529 stream_putc (s, 4);
2530 stream_putl (s, attr->med);
2531 }
2532
2533 /* Local preference. */
2534 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2535 {
2536 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2537 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2538 stream_putc (s, 4);
2539 stream_putl (s, attr->local_pref);
2540 }
2541
2542 /* Atomic aggregate. */
2543 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2544 {
2545 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2546 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2547 stream_putc (s, 0);
2548 }
2549
2550 /* Aggregator. */
2551 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2552 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002553 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002554 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2555 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002556 stream_putc (s, 8);
2557 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002558 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002559 }
2560
2561 /* Community attribute. */
2562 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2563 {
2564 if (attr->community->size * 4 > 255)
2565 {
2566 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2567 stream_putc (s, BGP_ATTR_COMMUNITIES);
2568 stream_putw (s, attr->community->size * 4);
2569 }
2570 else
2571 {
2572 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2573 stream_putc (s, BGP_ATTR_COMMUNITIES);
2574 stream_putc (s, attr->community->size * 4);
2575 }
2576 stream_put (s, attr->community->val, attr->community->size * 4);
2577 }
2578
paula3845922003-10-18 01:30:50 +00002579#ifdef HAVE_IPV6
2580 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002581 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2582 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002583 {
2584 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002585 struct attr_extra *attre = attr->extra;
2586
paula3845922003-10-18 01:30:50 +00002587 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2588 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002589 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002590
2591 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002592 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002593 stream_putw(s, AFI_IP6); /* AFI */
2594 stream_putc(s, SAFI_UNICAST); /* SAFI */
2595
2596 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002597 stream_putc(s, attre->mp_nexthop_len);
2598 stream_put(s, &attre->mp_nexthop_global, 16);
2599 if (attre->mp_nexthop_len == 32)
2600 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002601
2602 /* SNPA */
2603 stream_putc(s, 0);
2604
2605 /* Prefix */
2606 stream_put_prefix(s, prefix);
2607
2608 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002609 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002610 }
2611#endif /* HAVE_IPV6 */
2612
paul718e3742002-12-13 20:15:29 +00002613 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002614 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002615 stream_putw_at (s, cp, len);
2616}