blob: 4967e09a679b075d65ea5481ae167e805aea6607 [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
Denis Ovsienko0f572cd2011-10-26 19:34:30 +04001357 bgp_notify_send_with_data (peer,
1358 BGP_NOTIFY_UPDATE_ERR,
1359 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1360 startp, total);
paul718e3742002-12-13 20:15:29 +00001361 return -1;
1362 }
1363
Paul Jakmafb982c22007-05-04 20:15:47 +00001364 (bgp_attr_extra_get (attr))->originator_id.s_addr
1365 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001366
1367 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1368
1369 return 0;
1370}
1371
1372/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001373static int
paul718e3742002-12-13 20:15:29 +00001374bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001375 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001376{
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001377 bgp_size_t total;
1378
1379 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1380 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001381 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001382 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001383 bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001384 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1385 return -1;
1386 }
paul718e3742002-12-13 20:15:29 +00001387 /* Check length. */
1388 if (length % 4)
1389 {
1390 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1391
Denis Ovsienko0f572cd2011-10-26 19:34:30 +04001392 bgp_notify_send_with_data (peer,
1393 BGP_NOTIFY_UPDATE_ERR,
1394 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1395 startp, total);
paul718e3742002-12-13 20:15:29 +00001396 return -1;
1397 }
1398
Paul Jakmafb982c22007-05-04 20:15:47 +00001399 (bgp_attr_extra_get (attr))->cluster
1400 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001401
paul9985f832005-02-09 15:51:56 +00001402 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001403
1404 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1405
1406 return 0;
1407}
1408
1409/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001410int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001411bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1412 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001413{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001414 afi_t afi;
1415 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001416 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001417 size_t start;
paul718e3742002-12-13 20:15:29 +00001418 int ret;
1419 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001420 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001421 bgp_size_t total;
1422
1423 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1424 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001425 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001426 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001427 bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_REACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001428 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1429 return -1;
1430 }
paul718e3742002-12-13 20:15:29 +00001431 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001432 s = BGP_INPUT(peer);
1433 start = stream_get_getp(s);
1434
1435 /* safe to read statically sized header? */
1436#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001437#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001438 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001439 {
1440 zlog_info ("%s: %s sent invalid length, %lu",
1441 __func__, peer->host, (unsigned long)length);
1442 return -1;
1443 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001444
paul718e3742002-12-13 20:15:29 +00001445 /* Load AFI, SAFI. */
1446 afi = stream_getw (s);
1447 safi = stream_getc (s);
1448
1449 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001450 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001451
Paul Jakma03292802008-06-07 20:37:10 +00001452 if (LEN_LEFT < attre->mp_nexthop_len)
1453 {
1454 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1455 __func__, peer->host, attre->mp_nexthop_len);
1456 return -1;
1457 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001458
paul718e3742002-12-13 20:15:29 +00001459 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001460 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001461 {
1462 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001463 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001464 /* Probably needed for RFC 2283 */
1465 if (attr->nexthop.s_addr == 0)
1466 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001467 break;
1468 case 12:
1469 {
1470 u_int32_t rd_high;
1471 u_int32_t rd_low;
1472
1473 rd_high = stream_getl (s);
1474 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001475 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001476 }
1477 break;
1478#ifdef HAVE_IPV6
1479 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001480 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001481 break;
1482 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001483 stream_get (&attre->mp_nexthop_global, s, 16);
1484 stream_get (&attre->mp_nexthop_local, s, 16);
1485 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001486 {
1487 char buf1[INET6_ADDRSTRLEN];
1488 char buf2[INET6_ADDRSTRLEN];
1489
1490 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001491 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 +00001492 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001493 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001494 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001495 buf2, INET6_ADDRSTRLEN));
1496
Paul Jakmafb982c22007-05-04 20:15:47 +00001497 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001498 }
1499 break;
1500#endif /* HAVE_IPV6 */
1501 default:
Paul Jakma03292802008-06-07 20:37:10 +00001502 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1503 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001504 return -1;
paul718e3742002-12-13 20:15:29 +00001505 }
1506
Paul Jakma03292802008-06-07 20:37:10 +00001507 if (!LEN_LEFT)
1508 {
1509 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1510 __func__, peer->host);
1511 return -1;
1512 }
paul718e3742002-12-13 20:15:29 +00001513
Paul Jakma6e4ab122007-04-10 19:36:48 +00001514 {
1515 u_char val;
1516 if ((val = stream_getc (s)))
1517 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1518 peer->host, val);
1519 }
1520
1521 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001522 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001523 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001524 {
1525 zlog_info ("%s: (%s) Failed to read NLRI",
1526 __func__, peer->host);
1527 return -1;
1528 }
paul718e3742002-12-13 20:15:29 +00001529
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001530 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001531 {
1532 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001533 if (ret < 0)
1534 {
1535 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1536 __func__, peer->host);
1537 return -1;
1538 }
paul718e3742002-12-13 20:15:29 +00001539 }
1540
1541 mp_update->afi = afi;
1542 mp_update->safi = safi;
1543 mp_update->nlri = stream_pnt (s);
1544 mp_update->length = nlri_len;
1545
paul9985f832005-02-09 15:51:56 +00001546 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001547
1548 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001549#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001550}
1551
1552/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001553int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001554bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1555 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001556 struct bgp_nlri *mp_withdraw)
1557{
1558 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001559 afi_t afi;
1560 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001561 u_int16_t withdraw_len;
1562 int ret;
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001563 bgp_size_t total;
1564
1565 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1566 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001567 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001568 {
Denis Ovsienko26f5e782011-10-23 22:32:44 +04001569 bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_UNREACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001570 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1571 return -1;
1572 }
paul718e3742002-12-13 20:15:29 +00001573
1574 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001575
1576#define BGP_MP_UNREACH_MIN_SIZE 3
1577 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1578 return -1;
1579
paul718e3742002-12-13 20:15:29 +00001580 afi = stream_getw (s);
1581 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001582
1583 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001584
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001585 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001586 {
1587 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1588 if (ret < 0)
1589 return -1;
1590 }
1591
1592 mp_withdraw->afi = afi;
1593 mp_withdraw->safi = safi;
1594 mp_withdraw->nlri = stream_pnt (s);
1595 mp_withdraw->length = withdraw_len;
1596
paul9985f832005-02-09 15:51:56 +00001597 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001598
1599 return 0;
1600}
1601
1602/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001603static int
paul718e3742002-12-13 20:15:29 +00001604bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1605 struct attr *attr, u_char flag)
1606{
1607 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001608 {
1609 if (attr->extra)
1610 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001611 /* Empty extcomm doesn't seem to be invalid per se */
1612 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001613 }
Paul Jakmafc097162010-12-05 17:17:26 +00001614
1615 (bgp_attr_extra_get (attr))->ecommunity =
1616 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1617 /* XXX: fix ecommunity_parse to use stream API */
1618 stream_forward_getp (peer->ibuf, length);
1619
1620 if (!attr->extra->ecommunity)
1621 return -1;
1622
paul718e3742002-12-13 20:15:29 +00001623 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1624
1625 return 0;
1626}
1627
1628/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001629static int
paul718e3742002-12-13 20:15:29 +00001630bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1631 u_char type, bgp_size_t length, u_char *startp)
1632{
1633 bgp_size_t total;
1634 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001635 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001636
hassof4184462005-02-01 20:13:16 +00001637 if (BGP_DEBUG (normal, NORMAL))
1638 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1639 peer->host, type, length);
1640
paul718e3742002-12-13 20:15:29 +00001641 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001642 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001643 "Unknown attribute type %d length %d is received", type, length);
1644
1645 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001646 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001647
1648 /* Adjest total length to include type and length. */
1649 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1650
1651 /* If any of the mandatory well-known attributes are not recognized,
1652 then the Error Subcode is set to Unrecognized Well-known
1653 Attribute. The Data field contains the unrecognized attribute
1654 (type, length and value). */
1655 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1656 {
1657 /* Adjust startp to do not include flag value. */
1658 bgp_notify_send_with_data (peer,
1659 BGP_NOTIFY_UPDATE_ERR,
1660 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1661 startp, total);
1662 return -1;
1663 }
1664
1665 /* Unrecognized non-transitive optional attributes must be quietly
1666 ignored and not passed along to other BGP peers. */
1667 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1668 return 0;
1669
1670 /* If a path with recognized transitive optional attribute is
1671 accepted and passed along to other BGP peers and the Partial bit
1672 in the Attribute Flags octet is set to 1 by some previous AS, it
1673 is not set back to 0 by the current AS. */
1674 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1675
1676 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001677 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001678 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001679
Paul Jakmafb982c22007-05-04 20:15:47 +00001680 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001681
1682 if (transit->val)
1683 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1684 transit->length + total);
1685 else
1686 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1687
1688 memcpy (transit->val + transit->length, startp, total);
1689 transit->length += total;
1690
1691 return 0;
1692}
1693
1694/* Read attribute of update packet. This function is called from
1695 bgp_update() in bgpd.c. */
1696int
1697bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1698 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1699{
1700 int ret;
1701 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001702 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001703 bgp_size_t length;
1704 u_char *startp, *endp;
1705 u_char *attr_endp;
1706 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001707 /* we need the as4_path only until we have synthesized the as_path with it */
1708 /* same goes for as4_aggregator */
1709 struct aspath *as4_path = NULL;
1710 as_t as4_aggregator = 0;
1711 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001712
1713 /* Initialize bitmap. */
1714 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1715
1716 /* End pointer of BGP attribute. */
1717 endp = BGP_INPUT_PNT (peer) + size;
1718
1719 /* Get attributes to the end of attribute length. */
1720 while (BGP_INPUT_PNT (peer) < endp)
1721 {
1722 /* Check remaining length check.*/
1723 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1724 {
gdtc29fdba2004-12-09 14:46:46 +00001725 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001726 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001727 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001728 peer->host,
1729 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001730
1731 bgp_notify_send (peer,
1732 BGP_NOTIFY_UPDATE_ERR,
1733 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1734 return -1;
1735 }
1736
1737 /* Fetch attribute flag and type. */
1738 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001739 /* "The lower-order four bits of the Attribute Flags octet are
1740 unused. They MUST be zero when sent and MUST be ignored when
1741 received." */
1742 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001743 type = stream_getc (BGP_INPUT (peer));
1744
Paul Jakma370b64a2007-12-22 16:49:52 +00001745 /* Check whether Extended-Length applies and is in bounds */
1746 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1747 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1748 {
1749 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001750 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001751 peer->host,
1752 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1753
1754 bgp_notify_send (peer,
1755 BGP_NOTIFY_UPDATE_ERR,
1756 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1757 return -1;
1758 }
1759
paul718e3742002-12-13 20:15:29 +00001760 /* Check extended attribue length bit. */
1761 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1762 length = stream_getw (BGP_INPUT (peer));
1763 else
1764 length = stream_getc (BGP_INPUT (peer));
1765
1766 /* If any attribute appears more than once in the UPDATE
1767 message, then the Error Subcode is set to Malformed Attribute
1768 List. */
1769
1770 if (CHECK_BITMAP (seen, type))
1771 {
1772 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001773 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001774 peer->host, type);
1775
1776 bgp_notify_send (peer,
1777 BGP_NOTIFY_UPDATE_ERR,
1778 BGP_NOTIFY_UPDATE_MAL_ATTR);
1779 return -1;
1780 }
1781
1782 /* Set type to bitmap to check duplicate attribute. `type' is
1783 unsigned char so it never overflow bitmap range. */
1784
1785 SET_BITMAP (seen, type);
1786
1787 /* Overflow check. */
1788 attr_endp = BGP_INPUT_PNT (peer) + length;
1789
1790 if (attr_endp > endp)
1791 {
1792 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001793 "%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 +00001794 bgp_notify_send (peer,
1795 BGP_NOTIFY_UPDATE_ERR,
1796 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1797 return -1;
1798 }
1799
1800 /* OK check attribute and store it's value. */
1801 switch (type)
1802 {
1803 case BGP_ATTR_ORIGIN:
1804 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1805 break;
1806 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001807 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1808 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001809 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001810 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001811 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1812 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001813 break;
paul718e3742002-12-13 20:15:29 +00001814 case BGP_ATTR_NEXT_HOP:
1815 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1816 break;
1817 case BGP_ATTR_MULTI_EXIT_DISC:
1818 ret = bgp_attr_med (peer, length, attr, flag, startp);
1819 break;
1820 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001821 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001822 break;
1823 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001824 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001825 break;
1826 case BGP_ATTR_AGGREGATOR:
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001827 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001828 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001829 case BGP_ATTR_AS4_AGGREGATOR:
1830 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1831 break;
paul718e3742002-12-13 20:15:29 +00001832 case BGP_ATTR_COMMUNITIES:
1833 ret = bgp_attr_community (peer, length, attr, flag);
1834 break;
1835 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienko5de17192011-09-30 15:08:54 +04001836 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001837 break;
1838 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001839 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001840 break;
1841 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001842 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001843 break;
1844 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001845 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001846 break;
1847 case BGP_ATTR_EXT_COMMUNITIES:
1848 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1849 break;
1850 default:
1851 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1852 break;
1853 }
1854
1855 /* If error occured immediately return to the caller. */
1856 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001857 {
1858 zlog (peer->log, LOG_WARNING,
1859 "%s: Attribute %s, parse error",
1860 peer->host,
1861 LOOKUP (attr_str, type));
1862 bgp_notify_send (peer,
1863 BGP_NOTIFY_UPDATE_ERR,
1864 BGP_NOTIFY_UPDATE_MAL_ATTR);
1865 return ret;
1866 }
paul718e3742002-12-13 20:15:29 +00001867
1868 /* Check the fetched length. */
1869 if (BGP_INPUT_PNT (peer) != attr_endp)
1870 {
1871 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001872 "%s: BGP attribute %s, fetch error",
1873 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001874 bgp_notify_send (peer,
1875 BGP_NOTIFY_UPDATE_ERR,
1876 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1877 return -1;
1878 }
1879 }
1880
1881 /* Check final read pointer is same as end pointer. */
1882 if (BGP_INPUT_PNT (peer) != endp)
1883 {
1884 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001885 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001886 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001887 bgp_notify_send (peer,
1888 BGP_NOTIFY_UPDATE_ERR,
1889 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1890 return -1;
1891 }
1892
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001893 /*
1894 * At this place we can see whether we got AS4_PATH and/or
1895 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1896 * We can not do this before we've read all attributes because
1897 * the as4 handling does not say whether AS4_PATH has to be sent
1898 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1899 * in relationship to AGGREGATOR.
1900 * So, to be defensive, we are not relying on any order and read
1901 * all attributes first, including these 32bit ones, and now,
1902 * afterwards, we look what and if something is to be done for as4.
1903 */
1904 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1905 as4_aggregator, &as4_aggregator_addr))
1906 return -1;
1907
1908 /* At this stage, we have done all fiddling with as4, and the
1909 * resulting info is in attr->aggregator resp. attr->aspath
1910 * so we can chuck as4_aggregator and as4_path alltogether in
1911 * order to save memory
1912 */
1913 if ( as4_path )
1914 {
1915 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1916 as4_path = NULL;
1917 /* The flag that we got this is still there, but that does not
1918 * do any trouble
1919 */
1920 }
1921 /*
1922 * The "rest" of the code does nothing with as4_aggregator.
1923 * there is no memory attached specifically which is not part
1924 * of the attr.
1925 * so ignoring just means do nothing.
1926 */
1927 /*
1928 * Finally do the checks on the aspath we did not do yet
1929 * because we waited for a potentially synthesized aspath.
1930 */
1931 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1932 {
1933 ret = bgp_attr_aspath_check( peer, attr );
1934 if ( ret < 0 )
1935 return ret;
1936 }
1937
paul718e3742002-12-13 20:15:29 +00001938 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001939 if (attr->extra && attr->extra->transit)
1940 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001941
1942 return 0;
1943}
1944
1945/* Well-known attribute check. */
1946int
1947bgp_attr_check (struct peer *peer, struct attr *attr)
1948{
1949 u_char type = 0;
1950
1951 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1952 type = BGP_ATTR_ORIGIN;
1953
1954 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1955 type = BGP_ATTR_AS_PATH;
1956
1957 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1958 type = BGP_ATTR_NEXT_HOP;
1959
1960 if (peer_sort (peer) == BGP_PEER_IBGP
1961 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1962 type = BGP_ATTR_LOCAL_PREF;
1963
1964 if (type)
1965 {
1966 zlog (peer->log, LOG_WARNING,
1967 "%s Missing well-known attribute %d.",
1968 peer->host, type);
1969 bgp_notify_send_with_data (peer,
1970 BGP_NOTIFY_UPDATE_ERR,
1971 BGP_NOTIFY_UPDATE_MISS_ATTR,
1972 &type, 1);
1973 return -1;
1974 }
1975 return 0;
1976}
1977
1978int stream_put_prefix (struct stream *, struct prefix *);
1979
1980/* Make attribute packet. */
1981bgp_size_t
1982bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1983 struct stream *s, struct attr *attr, struct prefix *p,
1984 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001985 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001986{
paulfe69a502005-09-10 16:55:02 +00001987 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001988 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001989 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001990 int send_as4_path = 0;
1991 int send_as4_aggregator = 0;
1992 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001993
1994 if (! bgp)
1995 bgp = bgp_get_default ();
1996
1997 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001998 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001999
2000 /* Origin attribute. */
2001 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2002 stream_putc (s, BGP_ATTR_ORIGIN);
2003 stream_putc (s, 1);
2004 stream_putc (s, attr->origin);
2005
2006 /* AS path attribute. */
2007
2008 /* If remote-peer is EBGP */
2009 if (peer_sort (peer) == BGP_PEER_EBGP
2010 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002011 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002012 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002013 {
2014 aspath = aspath_dup (attr->aspath);
2015
2016 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2017 {
2018 /* Strip the confed info, and then stuff our path CONFED_ID
2019 on the front */
2020 aspath = aspath_delete_confed_seq (aspath);
2021 aspath = aspath_add_seq (aspath, bgp->confed_id);
2022 }
2023 else
2024 {
2025 aspath = aspath_add_seq (aspath, peer->local_as);
2026 if (peer->change_local_as)
2027 aspath = aspath_add_seq (aspath, peer->change_local_as);
2028 }
2029 }
2030 else if (peer_sort (peer) == BGP_PEER_CONFED)
2031 {
2032 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2033 aspath = aspath_dup (attr->aspath);
2034 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2035 }
2036 else
2037 aspath = attr->aspath;
2038
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002039 /* If peer is not AS4 capable, then:
2040 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2041 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2042 * types are in it (i.e. exclude them if they are there)
2043 * AND do this only if there is at least one asnum > 65535 in the path!
2044 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2045 * all ASnums > 65535 to BGP_AS_TRANS
2046 */
paul718e3742002-12-13 20:15:29 +00002047
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002048 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2049 stream_putc (s, BGP_ATTR_AS_PATH);
2050 aspath_sizep = stream_get_endp (s);
2051 stream_putw (s, 0);
2052 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2053
2054 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2055 * in the path
2056 */
2057 if (!use32bit && aspath_has_as4 (aspath))
2058 send_as4_path = 1; /* we'll do this later, at the correct place */
2059
paul718e3742002-12-13 20:15:29 +00002060 /* Nexthop attribute. */
2061 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2062 {
2063 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2064 stream_putc (s, BGP_ATTR_NEXT_HOP);
2065 stream_putc (s, 4);
2066 if (safi == SAFI_MPLS_VPN)
2067 {
2068 if (attr->nexthop.s_addr == 0)
2069 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2070 else
2071 stream_put_ipv4 (s, attr->nexthop.s_addr);
2072 }
2073 else
2074 stream_put_ipv4 (s, attr->nexthop.s_addr);
2075 }
2076
2077 /* MED attribute. */
2078 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2079 {
2080 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2081 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2082 stream_putc (s, 4);
2083 stream_putl (s, attr->med);
2084 }
2085
2086 /* Local preference. */
2087 if (peer_sort (peer) == BGP_PEER_IBGP ||
2088 peer_sort (peer) == BGP_PEER_CONFED)
2089 {
2090 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2091 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2092 stream_putc (s, 4);
2093 stream_putl (s, attr->local_pref);
2094 }
2095
2096 /* Atomic aggregate. */
2097 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2098 {
2099 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2100 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2101 stream_putc (s, 0);
2102 }
2103
2104 /* Aggregator. */
2105 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2106 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002107 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002108
2109 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002110 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2111 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002112
2113 if (use32bit)
2114 {
2115 /* AS4 capable peer */
2116 stream_putc (s, 8);
2117 stream_putl (s, attr->extra->aggregator_as);
2118 }
2119 else
2120 {
2121 /* 2-byte AS peer */
2122 stream_putc (s, 6);
2123
2124 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2125 if ( attr->extra->aggregator_as > 65535 )
2126 {
2127 stream_putw (s, BGP_AS_TRANS);
2128
2129 /* we have to send AS4_AGGREGATOR, too.
2130 * we'll do that later in order to send attributes in ascending
2131 * order.
2132 */
2133 send_as4_aggregator = 1;
2134 }
2135 else
2136 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2137 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002138 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002139 }
2140
2141 /* Community attribute. */
2142 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2143 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2144 {
2145 if (attr->community->size * 4 > 255)
2146 {
2147 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2148 stream_putc (s, BGP_ATTR_COMMUNITIES);
2149 stream_putw (s, attr->community->size * 4);
2150 }
2151 else
2152 {
2153 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2154 stream_putc (s, BGP_ATTR_COMMUNITIES);
2155 stream_putc (s, attr->community->size * 4);
2156 }
2157 stream_put (s, attr->community->val, attr->community->size * 4);
2158 }
2159
2160 /* Route Reflector. */
2161 if (peer_sort (peer) == BGP_PEER_IBGP
2162 && from
2163 && peer_sort (from) == BGP_PEER_IBGP)
2164 {
2165 /* Originator ID. */
2166 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2167 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2168 stream_putc (s, 4);
2169
2170 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002171 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002172 else
2173 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002174
2175 /* Cluster list. */
2176 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2177 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2178
Paul Jakma9eda90c2007-08-30 13:36:17 +00002179 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002180 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002181 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002182 /* If this peer configuration's parent BGP has cluster_id. */
2183 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2184 stream_put_in_addr (s, &bgp->cluster_id);
2185 else
2186 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002187 stream_put (s, attr->extra->cluster->list,
2188 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002189 }
2190 else
2191 {
2192 stream_putc (s, 4);
2193 /* If this peer configuration's parent BGP has cluster_id. */
2194 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2195 stream_put_in_addr (s, &bgp->cluster_id);
2196 else
2197 stream_put_in_addr (s, &bgp->router_id);
2198 }
2199 }
2200
2201#ifdef HAVE_IPV6
2202 /* If p is IPv6 address put it into attribute. */
2203 if (p->family == AF_INET6)
2204 {
2205 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002206 struct attr_extra *attre = attr->extra;
2207
2208 assert (attr->extra);
2209
paul718e3742002-12-13 20:15:29 +00002210 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2211 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002212 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002213 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002214 stream_putw (s, AFI_IP6); /* AFI */
2215 stream_putc (s, safi); /* SAFI */
2216
Paul Jakmafb982c22007-05-04 20:15:47 +00002217 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002218
Paul Jakmafb982c22007-05-04 20:15:47 +00002219 if (attre->mp_nexthop_len == 16)
2220 stream_put (s, &attre->mp_nexthop_global, 16);
2221 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002222 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002223 stream_put (s, &attre->mp_nexthop_global, 16);
2224 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002225 }
2226
2227 /* SNPA */
2228 stream_putc (s, 0);
2229
paul718e3742002-12-13 20:15:29 +00002230 /* Prefix write. */
2231 stream_put_prefix (s, p);
2232
2233 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002234 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002235 }
2236#endif /* HAVE_IPV6 */
2237
2238 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2239 {
2240 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002241
2242 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2243 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002244 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002245 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002246 stream_putw (s, AFI_IP); /* AFI */
2247 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2248
2249 stream_putc (s, 4);
2250 stream_put_ipv4 (s, attr->nexthop.s_addr);
2251
2252 /* SNPA */
2253 stream_putc (s, 0);
2254
paul718e3742002-12-13 20:15:29 +00002255 /* Prefix write. */
2256 stream_put_prefix (s, p);
2257
2258 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002259 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002260 }
2261
2262 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2263 {
2264 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002265
2266 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2267 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002268 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002269 stream_putc (s, 0); /* Length of this attribute. */
2270 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002271 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002272
2273 stream_putc (s, 12);
2274 stream_putl (s, 0);
2275 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002276 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002277
2278 /* SNPA */
2279 stream_putc (s, 0);
2280
paul718e3742002-12-13 20:15:29 +00002281 /* Tag, RD, Prefix write. */
2282 stream_putc (s, p->prefixlen + 88);
2283 stream_put (s, tag, 3);
2284 stream_put (s, prd->val, 8);
2285 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2286
2287 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002288 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002289 }
2290
2291 /* Extended Communities attribute. */
2292 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2293 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2294 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002295 struct attr_extra *attre = attr->extra;
2296
2297 assert (attre);
2298
2299 if (peer_sort (peer) == BGP_PEER_IBGP
2300 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002301 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002302 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002303 {
2304 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2305 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002306 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002307 }
2308 else
2309 {
2310 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2311 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002312 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002313 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002314 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002315 }
2316 else
2317 {
paul5228ad22004-06-04 17:58:18 +00002318 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002319 int tbit;
2320 int ecom_tr_size = 0;
2321 int i;
2322
Paul Jakmafb982c22007-05-04 20:15:47 +00002323 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002324 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002325 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002326 tbit = *pnt;
2327
2328 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2329 continue;
2330
2331 ecom_tr_size++;
2332 }
2333
2334 if (ecom_tr_size)
2335 {
2336 if (ecom_tr_size * 8 > 255)
2337 {
2338 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2339 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2340 stream_putw (s, ecom_tr_size * 8);
2341 }
2342 else
2343 {
2344 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2345 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2346 stream_putc (s, ecom_tr_size * 8);
2347 }
2348
Paul Jakmafb982c22007-05-04 20:15:47 +00002349 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002350 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002351 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002352 tbit = *pnt;
2353
2354 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2355 continue;
2356
2357 stream_put (s, pnt, 8);
2358 }
2359 }
paul718e3742002-12-13 20:15:29 +00002360 }
paul718e3742002-12-13 20:15:29 +00002361 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002362
2363 if ( send_as4_path )
2364 {
2365 /* If the peer is NOT As4 capable, AND */
2366 /* there are ASnums > 65535 in path THEN
2367 * give out AS4_PATH */
2368
2369 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2370 * path segments!
2371 * Hm, I wonder... confederation things *should* only be at
2372 * the beginning of an aspath, right? Then we should use
2373 * aspath_delete_confed_seq for this, because it is already
2374 * there! (JK)
2375 * Folks, talk to me: what is reasonable here!?
2376 */
2377 aspath = aspath_delete_confed_seq (aspath);
2378
2379 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2380 stream_putc (s, BGP_ATTR_AS4_PATH);
2381 aspath_sizep = stream_get_endp (s);
2382 stream_putw (s, 0);
2383 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2384 }
2385
2386 if (aspath != attr->aspath)
2387 aspath_free (aspath);
2388
2389 if ( send_as4_aggregator )
2390 {
2391 assert (attr->extra);
2392
2393 /* send AS4_AGGREGATOR, at this place */
2394 /* this section of code moved here in order to ensure the correct
2395 * *ascending* order of attributes
2396 */
2397 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2398 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2399 stream_putc (s, 8);
2400 stream_putl (s, attr->extra->aggregator_as);
2401 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2402 }
Paul Jakma41367172007-08-06 15:24:51 +00002403
paul718e3742002-12-13 20:15:29 +00002404 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002405 if (attr->extra && attr->extra->transit)
2406 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002407
2408 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002409 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002410}
2411
2412bgp_size_t
2413bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2414 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002415 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002416{
2417 unsigned long cp;
2418 unsigned long attrlen_pnt;
2419 bgp_size_t size;
2420
paul9985f832005-02-09 15:51:56 +00002421 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002422
2423 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2424 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2425
paul9985f832005-02-09 15:51:56 +00002426 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002427 stream_putc (s, 0); /* Length of this attribute. */
2428
2429 stream_putw (s, family2afi (p->family));
2430
2431 if (safi == SAFI_MPLS_VPN)
2432 {
2433 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002434 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002435
2436 /* prefix. */
2437 stream_putc (s, p->prefixlen + 88);
2438 stream_put (s, tag, 3);
2439 stream_put (s, prd->val, 8);
2440 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2441 }
2442 else
2443 {
2444 /* SAFI */
2445 stream_putc (s, safi);
2446
2447 /* prefix */
2448 stream_put_prefix (s, p);
2449 }
2450
2451 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002452 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002453 stream_putc_at (s, attrlen_pnt, size);
2454
paul9985f832005-02-09 15:51:56 +00002455 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002456}
2457
2458/* Initialization of attribute. */
2459void
paulfe69a502005-09-10 16:55:02 +00002460bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002461{
paul718e3742002-12-13 20:15:29 +00002462 aspath_init ();
2463 attrhash_init ();
2464 community_init ();
2465 ecommunity_init ();
2466 cluster_init ();
2467 transit_init ();
2468}
2469
Chris Caputo228da422009-07-18 05:44:03 +00002470void
2471bgp_attr_finish (void)
2472{
2473 aspath_finish ();
2474 attrhash_finish ();
2475 community_finish ();
2476 ecommunity_finish ();
2477 cluster_finish ();
2478 transit_finish ();
2479}
2480
paul718e3742002-12-13 20:15:29 +00002481/* Make attribute packet. */
2482void
paula3845922003-10-18 01:30:50 +00002483bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2484 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002485{
2486 unsigned long cp;
2487 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002488 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002489 struct aspath *aspath;
2490
2491 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002492 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002493
2494 /* Place holder of length. */
2495 stream_putw (s, 0);
2496
2497 /* Origin attribute. */
2498 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2499 stream_putc (s, BGP_ATTR_ORIGIN);
2500 stream_putc (s, 1);
2501 stream_putc (s, attr->origin);
2502
2503 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002504
2505 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2506 stream_putc (s, BGP_ATTR_AS_PATH);
2507 aspath_lenp = stream_get_endp (s);
2508 stream_putw (s, 0);
2509
2510 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002511
2512 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002513 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2514 if(prefix != NULL
2515#ifdef HAVE_IPV6
2516 && prefix->family != AF_INET6
2517#endif /* HAVE_IPV6 */
2518 )
2519 {
2520 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2521 stream_putc (s, BGP_ATTR_NEXT_HOP);
2522 stream_putc (s, 4);
2523 stream_put_ipv4 (s, attr->nexthop.s_addr);
2524 }
paul718e3742002-12-13 20:15:29 +00002525
2526 /* MED attribute. */
2527 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2528 {
2529 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2530 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2531 stream_putc (s, 4);
2532 stream_putl (s, attr->med);
2533 }
2534
2535 /* Local preference. */
2536 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2537 {
2538 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2539 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2540 stream_putc (s, 4);
2541 stream_putl (s, attr->local_pref);
2542 }
2543
2544 /* Atomic aggregate. */
2545 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2546 {
2547 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2548 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2549 stream_putc (s, 0);
2550 }
2551
2552 /* Aggregator. */
2553 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2554 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002555 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002556 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2557 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002558 stream_putc (s, 8);
2559 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002560 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002561 }
2562
2563 /* Community attribute. */
2564 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2565 {
2566 if (attr->community->size * 4 > 255)
2567 {
2568 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2569 stream_putc (s, BGP_ATTR_COMMUNITIES);
2570 stream_putw (s, attr->community->size * 4);
2571 }
2572 else
2573 {
2574 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2575 stream_putc (s, BGP_ATTR_COMMUNITIES);
2576 stream_putc (s, attr->community->size * 4);
2577 }
2578 stream_put (s, attr->community->val, attr->community->size * 4);
2579 }
2580
paula3845922003-10-18 01:30:50 +00002581#ifdef HAVE_IPV6
2582 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002583 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2584 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002585 {
2586 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002587 struct attr_extra *attre = attr->extra;
2588
paula3845922003-10-18 01:30:50 +00002589 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2590 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002591 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002592
2593 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002594 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002595 stream_putw(s, AFI_IP6); /* AFI */
2596 stream_putc(s, SAFI_UNICAST); /* SAFI */
2597
2598 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002599 stream_putc(s, attre->mp_nexthop_len);
2600 stream_put(s, &attre->mp_nexthop_global, 16);
2601 if (attre->mp_nexthop_len == 32)
2602 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002603
2604 /* SNPA */
2605 stream_putc(s, 0);
2606
2607 /* Prefix */
2608 stream_put_prefix(s, prefix);
2609
2610 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002611 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002612 }
2613#endif /* HAVE_IPV6 */
2614
paul718e3742002-12-13 20:15:29 +00002615 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002616 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002617 stream_putw_at (s, cp, len);
2618}