blob: dae895d758d2e48358d4d71fd6c1a6bc350f195a [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]);
paul718e3742002-12-13 20:15:29 +000065
Stephen Hemminger9bddac42009-05-15 09:59:51 -070066static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000067
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 struct cluster_list *cluster;
73
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
76
77 if (cluster->length)
78 {
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
81 }
82 else
83 cluster->list = NULL;
84
85 cluster->refcnt = 0;
86
87 return cluster;
88}
89
90/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
103}
104
105int
106cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
107{
108 int i;
109
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
114}
115
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
123
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
126
127 while (length)
128 key += pnt[--length];
129
130 return key;
131}
132
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
Chris Caputo228da422009-07-18 05:44:03 +0000151#if 0
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
Stephen Hemminger393deb92008-08-18 14:13:29 -0700157 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
Chris Caputo228da422009-07-18 05:44:03 +0000170#endif
paul718e3742002-12-13 20:15:29 +0000171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
246 struct transit *ret;
247
248 if (transit->refcnt)
249 transit->refcnt--;
250
251 if (transit->refcnt == 0)
252 {
253 ret = hash_release (transit_hash, transit);
254 transit_free (transit);
255 }
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000259transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma923de652007-04-29 18:25:17 +0000261 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000262 unsigned int key = 0;
263 int length;
264 caddr_t pnt;
265
266 length = transit->length;
267 pnt = (caddr_t) transit->val;
268
269 while (length)
270 key += pnt[--length];
271
272 return key;
273}
274
paul94f2b392005-06-28 12:44:16 +0000275static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100276transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000277{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100278 const struct transit * transit1 = p1;
279 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000280
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100281 return (transit1->length == transit2->length &&
282 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000283}
284
paul94f2b392005-06-28 12:44:16 +0000285static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800286transit_init (void)
paul718e3742002-12-13 20:15:29 +0000287{
288 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
289}
Chris Caputo228da422009-07-18 05:44:03 +0000290
291static void
292transit_finish (void)
293{
294 hash_free (transit_hash);
295 transit_hash = NULL;
296}
paul718e3742002-12-13 20:15:29 +0000297
298/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700299static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000300
Paul Jakmafb982c22007-05-04 20:15:47 +0000301static struct attr_extra *
302bgp_attr_extra_new (void)
303{
304 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
305}
306
307void
308bgp_attr_extra_free (struct attr *attr)
309{
310 if (attr->extra)
311 {
312 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
313 attr->extra = NULL;
314 }
315}
316
317struct attr_extra *
318bgp_attr_extra_get (struct attr *attr)
319{
320 if (!attr->extra)
321 attr->extra = bgp_attr_extra_new();
322 return attr->extra;
323}
324
325/* Shallow copy of an attribute
326 * Though, not so shallow that it doesn't copy the contents
327 * of the attr_extra pointed to by 'extra'
328 */
329void
330bgp_attr_dup (struct attr *new, struct attr *orig)
331{
332 *new = *orig;
333 if (orig->extra)
334 {
335 new->extra = bgp_attr_extra_new();
336 *new->extra = *orig->extra;
337 }
338}
339
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000340unsigned long int
341attr_count (void)
342{
343 return attrhash->count;
344}
345
346unsigned long int
347attr_unknown_count (void)
348{
349 return transit_hash->count;
350}
351
paul718e3742002-12-13 20:15:29 +0000352unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000353attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000354{
Paul Jakma923de652007-04-29 18:25:17 +0000355 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000356 unsigned int key = 0;
357
358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000362
363 if (attr->extra)
364 {
365 key += attr->extra->aggregator_as;
366 key += attr->extra->aggregator_addr.s_addr;
367 key += attr->extra->weight;
368 key += attr->extra->mp_nexthop_global_in.s_addr;
369 }
370
paul718e3742002-12-13 20:15:29 +0000371 if (attr->aspath)
372 key += aspath_key_make (attr->aspath);
373 if (attr->community)
374 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000375
376 if (attr->extra)
377 {
378 if (attr->extra->ecommunity)
379 key += ecommunity_hash_make (attr->extra->ecommunity);
380 if (attr->extra->cluster)
381 key += cluster_hash_key_make (attr->extra->cluster);
382 if (attr->extra->transit)
383 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000384
385#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 {
387 int i;
388
389 key += attr->extra->mp_nexthop_len;
390 for (i = 0; i < 16; i++)
391 key += attr->extra->mp_nexthop_global.s6_addr[i];
392 for (i = 0; i < 16; i++)
393 key += attr->extra->mp_nexthop_local.s6_addr[i];
394 }
paul718e3742002-12-13 20:15:29 +0000395#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000396 }
paul718e3742002-12-13 20:15:29 +0000397
398 return key;
399}
400
401int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100402attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000403{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100404 const struct attr * attr1 = p1;
405 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000406
paul718e3742002-12-13 20:15:29 +0000407 if (attr1->flag == attr2->flag
408 && attr1->origin == attr2->origin
409 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000410 && attr1->aspath == attr2->aspath
411 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000412 && attr1->med == attr2->med
Paul Jakmae70e5752011-07-05 00:41:59 +0400413 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000414 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100415 const struct attr_extra *ae1 = attr1->extra;
416 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000417
418 if (ae1 && ae2
419 && ae1->aggregator_as == ae2->aggregator_as
420 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
421 && ae1->weight == ae2->weight
422#ifdef HAVE_IPV6
423 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
424 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
425 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
426#endif /* HAVE_IPV6 */
427 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
428 && ae1->ecommunity == ae2->ecommunity
429 && ae1->cluster == ae2->cluster
430 && ae1->transit == ae2->transit)
431 return 1;
432 else if (ae1 || ae2)
433 return 0;
434 /* neither attribute has extra attributes, so they're same */
435 return 1;
436 }
paul718e3742002-12-13 20:15:29 +0000437 else
438 return 0;
439}
440
paul94f2b392005-06-28 12:44:16 +0000441static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100442attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000443{
444 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
445}
446
paul94f2b392005-06-28 12:44:16 +0000447static void
Chris Caputo228da422009-07-18 05:44:03 +0000448attrhash_finish (void)
449{
450 hash_free (attrhash);
451 attrhash = NULL;
452}
453
454static void
paul718e3742002-12-13 20:15:29 +0000455attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
456{
457 struct attr *attr = backet->data;
458
459 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
460 inet_ntoa (attr->nexthop), VTY_NEWLINE);
461}
462
463void
464attr_show_all (struct vty *vty)
465{
466 hash_iterate (attrhash,
467 (void (*)(struct hash_backet *, void *))
468 attr_show_all_iterator,
469 vty);
470}
471
paul94f2b392005-06-28 12:44:16 +0000472static void *
Paul Jakma923de652007-04-29 18:25:17 +0000473bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000474{
Paul Jakma923de652007-04-29 18:25:17 +0000475 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000476 struct attr *attr;
477
478 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
479 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000480 if (val->extra)
481 {
482 attr->extra = bgp_attr_extra_new ();
483 *attr->extra = *val->extra;
484 }
paul718e3742002-12-13 20:15:29 +0000485 attr->refcnt = 0;
486 return attr;
487}
488
489/* Internet argument attribute. */
490struct attr *
491bgp_attr_intern (struct attr *attr)
492{
493 struct attr *find;
494
495 /* Intern referenced strucutre. */
496 if (attr->aspath)
497 {
498 if (! attr->aspath->refcnt)
499 attr->aspath = aspath_intern (attr->aspath);
500 else
501 attr->aspath->refcnt++;
502 }
503 if (attr->community)
504 {
505 if (! attr->community->refcnt)
506 attr->community = community_intern (attr->community);
507 else
508 attr->community->refcnt++;
509 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000510 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000511 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000512 struct attr_extra *attre = attr->extra;
513
514 if (attre->ecommunity)
515 {
516 if (! attre->ecommunity->refcnt)
517 attre->ecommunity = ecommunity_intern (attre->ecommunity);
518 else
519 attre->ecommunity->refcnt++;
520 }
521 if (attre->cluster)
522 {
523 if (! attre->cluster->refcnt)
524 attre->cluster = cluster_intern (attre->cluster);
525 else
526 attre->cluster->refcnt++;
527 }
528 if (attre->transit)
529 {
530 if (! attre->transit->refcnt)
531 attre->transit = transit_intern (attre->transit);
532 else
533 attre->transit->refcnt++;
534 }
paul718e3742002-12-13 20:15:29 +0000535 }
536
537 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
538 find->refcnt++;
539
540 return find;
541}
542
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544/* Make network statement's attribute. */
545struct attr *
546bgp_attr_default_set (struct attr *attr, u_char origin)
547{
548 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000549 bgp_attr_extra_get (attr);
550
paul718e3742002-12-13 20:15:29 +0000551 attr->origin = origin;
552 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
553 attr->aspath = aspath_empty ();
554 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000556 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
557#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000559#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000560
paul718e3742002-12-13 20:15:29 +0000561 return attr;
562}
563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564
paul718e3742002-12-13 20:15:29 +0000565/* Make network statement's attribute. */
566struct attr *
567bgp_attr_default_intern (u_char origin)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
572
573 memset (&attr, 0, sizeof (struct attr));
574 attre = bgp_attr_extra_get (&attr);
575
Paul Jakma03e214c2007-04-29 18:31:07 +0000576 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000577
578 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 bgp_attr_extra_free (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 aspath_unintern (new->aspath);
582 return new;
583}
584
585struct attr *
586bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
587 struct aspath *aspath,
588 struct community *community, int as_set)
589{
590 struct attr attr;
591 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000592 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000593
594 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000595 attre = bgp_attr_extra_get (&attr);
596
paul718e3742002-12-13 20:15:29 +0000597 /* Origin attribute. */
598 attr.origin = origin;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
600
601 /* AS path attribute. */
602 if (aspath)
603 attr.aspath = aspath_intern (aspath);
604 else
605 attr.aspath = aspath_empty ();
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
607
608 /* Next hop attribute. */
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
610
611 if (community)
612 {
613 attr.community = community;
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
615 }
616
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000618#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000619 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000620#endif
621 if (! as_set)
622 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
623 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
624 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000625 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000626 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 attre->aggregator_as = bgp->as;
628 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000629
630 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000631 bgp_attr_extra_free (&attr);
632
paul718e3742002-12-13 20:15:29 +0000633 aspath_unintern (new->aspath);
634 return new;
635}
636
637/* Free bgp attribute and aspath. */
638void
639bgp_attr_unintern (struct attr *attr)
640{
641 struct attr *ret;
642 struct aspath *aspath;
643 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000644 struct ecommunity *ecommunity = NULL;
645 struct cluster_list *cluster = NULL;
646 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000647
648 /* Decrement attribute reference. */
649 attr->refcnt--;
650 aspath = attr->aspath;
651 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000652 if (attr->extra)
653 {
654 ecommunity = attr->extra->ecommunity;
655 cluster = attr->extra->cluster;
656 transit = attr->extra->transit;
657 }
paul718e3742002-12-13 20:15:29 +0000658
659 /* If reference becomes zero then free attribute object. */
660 if (attr->refcnt == 0)
661 {
662 ret = hash_release (attrhash, attr);
663 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000664 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000665 XFREE (MTYPE_ATTR, attr);
666 }
667
668 /* aspath refcount shoud be decrement. */
669 if (aspath)
670 aspath_unintern (aspath);
671 if (community)
672 community_unintern (community);
673 if (ecommunity)
674 ecommunity_unintern (ecommunity);
675 if (cluster)
676 cluster_unintern (cluster);
677 if (transit)
678 transit_unintern (transit);
679}
680
681void
682bgp_attr_flush (struct attr *attr)
683{
684 if (attr->aspath && ! attr->aspath->refcnt)
685 aspath_free (attr->aspath);
686 if (attr->community && ! attr->community->refcnt)
687 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000688 if (attr->extra)
689 {
690 struct attr_extra *attre = attr->extra;
691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
692 ecommunity_free (attre->ecommunity);
693 if (attre->cluster && ! attre->cluster->refcnt)
694 cluster_free (attre->cluster);
695 if (attre->transit && ! attre->transit->refcnt)
696 transit_free (attre->transit);
697 }
paul718e3742002-12-13 20:15:29 +0000698}
699
700/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000701static int
paul718e3742002-12-13 20:15:29 +0000702bgp_attr_origin (struct peer *peer, bgp_size_t length,
703 struct attr *attr, u_char flag, u_char *startp)
704{
705 bgp_size_t total;
706
707 /* total is entire attribute length include Attribute Flags (1),
708 Attribute Type code (1) and Attribute length (1 or 2). */
709 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
710
711 /* If any recognized attribute has Attribute Flags that conflict
712 with the Attribute Type Code, then the Error Subcode is set to
713 Attribute Flags Error. The Data field contains the erroneous
714 attribute (type, length and value). */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400715 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400716 {
717 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
718 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
719 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
720 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
721 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
722 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
723 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
724 return -1;
725 }
paul718e3742002-12-13 20:15:29 +0000726
727 /* If any recognized attribute has Attribute Length that conflicts
728 with the expected length (based on the attribute type code), then
729 the Error Subcode is set to Attribute Length Error. The Data
730 field contains the erroneous attribute (type, length and
731 value). */
732 if (length != 1)
733 {
734 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
735 length);
736 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
737 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
738 startp, total);
739 return -1;
740 }
741
742 /* Fetch origin attribute. */
743 attr->origin = stream_getc (BGP_INPUT (peer));
744
745 /* If the ORIGIN attribute has an undefined value, then the Error
746 Subcode is set to Invalid Origin Attribute. The Data field
747 contains the unrecognized attribute (type, length and value). */
748 if ((attr->origin != BGP_ORIGIN_IGP)
749 && (attr->origin != BGP_ORIGIN_EGP)
750 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
751 {
752 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
753 attr->origin);
754
755 bgp_notify_send_with_data (peer,
756 BGP_NOTIFY_UPDATE_ERR,
757 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
758 startp, total);
759 return -1;
760 }
761
762 /* Set oring attribute flag. */
763 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
764
765 return 0;
766}
Chris Hallcddb8112010-08-09 22:31:37 +0400767/* Parse AS path information. This function is wrapper of aspath_parse.
768 *
769 * Parses AS_PATH or AS4_PATH.
770 *
771 * Returns: if valid: address of struct aspath in the hash of known aspaths,
772 * with reference count incremented.
773 * else: NULL
774 *
775 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
776 * have segments == NULL and str == zero length string (unique).
777 */
778static struct aspath *
paul718e3742002-12-13 20:15:29 +0000779bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400780 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000781{
Chris Hallcddb8112010-08-09 22:31:37 +0400782 u_char require ;
783 struct aspath *asp ;
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400784 bgp_size_t total;
785
786 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000787
Chris Hallcddb8112010-08-09 22:31:37 +0400788 /* Check the attribute flags */
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400789 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
790 {
791 zlog (peer->log, LOG_ERR,
792 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
793 bgp_notify_send_with_data (peer,
794 BGP_NOTIFY_UPDATE_ERR,
795 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
796 startp, total);
797 return NULL;
798 }
799
Chris Hallcddb8112010-08-09 22:31:37 +0400800 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
801 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000802
Chris Hallcddb8112010-08-09 22:31:37 +0400803 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000804 {
Chris Hallcddb8112010-08-09 22:31:37 +0400805 const char* path_type ;
Chris Hallcddb8112010-08-09 22:31:37 +0400806
807 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
808
809 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000810 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400811 "%s attribute flag isn't transitive %d", path_type, flag) ;
812
813 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
814 zlog (peer->log, LOG_ERR,
815 "%s attribute flag must %sbe optional %d", path_type,
816 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
817
paul718e3742002-12-13 20:15:29 +0000818 bgp_notify_send_with_data (peer,
819 BGP_NOTIFY_UPDATE_ERR,
820 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
821 startp, total);
paul718e3742002-12-13 20:15:29 +0000822
Chris Hallcddb8112010-08-09 22:31:37 +0400823 return NULL ;
824 } ;
825
826 /* Parse the AS_PATH/AS4_PATH body.
827 *
828 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
829 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000830 */
Chris Hallcddb8112010-08-09 22:31:37 +0400831 asp = aspath_parse (peer->ibuf, length,
832 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000833
Chris Hallcddb8112010-08-09 22:31:37 +0400834 if (asp != NULL)
835 {
836 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
837 : BGP_ATTR_AS_PATH) ;
838 }
839 else
paul718e3742002-12-13 20:15:29 +0000840 {
841 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400842
843 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000844 bgp_notify_send (peer,
845 BGP_NOTIFY_UPDATE_ERR,
846 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400847 } ;
paul718e3742002-12-13 20:15:29 +0000848
Chris Hallcddb8112010-08-09 22:31:37 +0400849 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000850}
851
852static int bgp_attr_aspath_check( struct peer *peer,
853 struct attr *attr)
854{
855 /* These checks were part of bgp_attr_aspath, but with
856 * as4 we should to check aspath things when
857 * aspath synthesizing with as4_path has already taken place.
858 * Otherwise we check ASPATH and use the synthesized thing, and that is
859 * not right.
860 * So do the checks later, i.e. here
861 */
862 struct bgp *bgp = peer->bgp;
863 struct aspath *aspath;
864
paul718e3742002-12-13 20:15:29 +0000865 bgp = peer->bgp;
866
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300867 /* Confederation sanity check. */
868 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
869 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
870 {
871 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
872 bgp_notify_send (peer,
873 BGP_NOTIFY_UPDATE_ERR,
874 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
875 return -1;
876 }
877
paul718e3742002-12-13 20:15:29 +0000878 /* First AS check for EBGP. */
879 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
880 {
881 if (peer_sort (peer) == BGP_PEER_EBGP
882 && ! aspath_firstas_check (attr->aspath, peer->as))
883 {
884 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400885 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000886 bgp_notify_send (peer,
887 BGP_NOTIFY_UPDATE_ERR,
888 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
889 return -1;
890 }
891 }
892
893 /* local-as prepend */
894 if (peer->change_local_as &&
895 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
896 {
897 aspath = aspath_dup (attr->aspath);
898 aspath = aspath_add_seq (aspath, peer->change_local_as);
899 aspath_unintern (attr->aspath);
900 attr->aspath = aspath_intern (aspath);
901 }
902
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903 return 0;
904
905}
906
paul718e3742002-12-13 20:15:29 +0000907/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000908static int
paul718e3742002-12-13 20:15:29 +0000909bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
910 struct attr *attr, u_char flag, u_char *startp)
911{
912 bgp_size_t total;
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400913 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000914
915 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
916
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400917 /* Flags check. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400918 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400919 {
920 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
921 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
922 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
923 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
924 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
925 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
926 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
927 return -1;
928 }
paul718e3742002-12-13 20:15:29 +0000929
930 /* Check nexthop attribute length. */
931 if (length != 4)
932 {
933 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
934 length);
935
936 bgp_notify_send_with_data (peer,
937 BGP_NOTIFY_UPDATE_ERR,
938 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
939 startp, total);
940 return -1;
941 }
942
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400943 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
944 attribute must result in a NOTIFICATION message (this is implemented below).
945 At the same time, semantically incorrect NEXT_HOP is more likely to be just
946 logged locally (this is implemented somewhere else). The UPDATE message
947 gets ignored in any of these cases. */
948 nexthop_n = stream_get_ipv4 (peer->ibuf);
949 nexthop_h = ntohl (nexthop_n);
950 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
951 {
952 char buf[INET_ADDRSTRLEN];
953 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
954 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
955 bgp_notify_send_with_data (peer,
956 BGP_NOTIFY_UPDATE_ERR,
957 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
958 startp, total);
959 return -1;
960 }
961
962 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +0000963 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
964
965 return 0;
966}
967
968/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000969static int
paul718e3742002-12-13 20:15:29 +0000970bgp_attr_med (struct peer *peer, bgp_size_t length,
971 struct attr *attr, u_char flag, u_char *startp)
972{
973 bgp_size_t total;
974
975 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
976
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400977 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400978 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400979 {
980 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
981 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
982 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
983 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
984 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
985 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
986 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
987 return -1;
988 }
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400989
paul718e3742002-12-13 20:15:29 +0000990 /* Length check. */
991 if (length != 4)
992 {
993 zlog (peer->log, LOG_ERR,
994 "MED attribute length isn't four [%d]", length);
995
996 bgp_notify_send_with_data (peer,
997 BGP_NOTIFY_UPDATE_ERR,
998 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
999 startp, total);
1000 return -1;
1001 }
1002
1003 attr->med = stream_getl (peer->ibuf);
1004
1005 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1006
1007 return 0;
1008}
1009
1010/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001011static int
paul718e3742002-12-13 20:15:29 +00001012bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001013 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001014{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001015 bgp_size_t total;
1016
1017 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1018 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001019 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001020 {
1021 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1022 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1023 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1024 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1025 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1026 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1027 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1028 return -1;
1029 }
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001030 /* Length check. */
1031 if (length != 4)
1032 {
1033 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
1034 bgp_notify_send_with_data (peer,
1035 BGP_NOTIFY_UPDATE_ERR,
1036 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1037 startp, total);
1038 return -1;
1039 }
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001040
paul718e3742002-12-13 20:15:29 +00001041 /* If it is contained in an UPDATE message that is received from an
1042 external peer, then this attribute MUST be ignored by the
1043 receiving speaker. */
1044 if (peer_sort (peer) == BGP_PEER_EBGP)
1045 {
paul9985f832005-02-09 15:51:56 +00001046 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001047 return 0;
1048 }
1049
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001050 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001051
1052 /* Set atomic aggregate flag. */
1053 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1054
1055 return 0;
1056}
1057
1058/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001059static int
paul718e3742002-12-13 20:15:29 +00001060bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001061 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001062{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001063 bgp_size_t total;
1064
1065 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1066 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001067 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001068 {
1069 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1070 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1071 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1072 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1073 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1074 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1075 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1076 return -1;
1077 }
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001078
1079 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001080 if (length != 0)
1081 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001082 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
1083 bgp_notify_send_with_data (peer,
1084 BGP_NOTIFY_UPDATE_ERR,
1085 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1086 startp, total);
paul718e3742002-12-13 20:15:29 +00001087 return -1;
1088 }
1089
1090 /* Set atomic aggregate flag. */
1091 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1092
1093 return 0;
1094}
1095
1096/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001097static int
paul718e3742002-12-13 20:15:29 +00001098bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001099 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001100{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001101 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001102 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001103 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001104
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001105 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001106 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1107 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1108 wantedlen = 8;
1109
1110 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001111 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001112 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
1113 bgp_notify_send_with_data (peer,
1114 BGP_NOTIFY_UPDATE_ERR,
1115 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1116 startp, total);
paul718e3742002-12-13 20:15:29 +00001117 return -1;
1118 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001119
1120 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1121 attre->aggregator_as = stream_getl (peer->ibuf);
1122 else
1123 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001124 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001125
1126 /* Set atomic aggregate flag. */
1127 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1128
1129 return 0;
1130}
1131
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001132/* New Aggregator attribute */
1133static int
1134bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1135 struct attr *attr, as_t *as4_aggregator_as,
1136 struct in_addr *as4_aggregator_addr)
1137{
1138 if (length != 8)
1139 {
1140 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1141
1142 bgp_notify_send (peer,
1143 BGP_NOTIFY_UPDATE_ERR,
1144 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1145 return -1;
1146 }
1147 *as4_aggregator_as = stream_getl (peer->ibuf);
1148 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1149
1150 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1151
1152 return 0;
1153}
1154
1155/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1156 */
1157static int
1158bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1159 struct aspath *as4_path, as_t as4_aggregator,
1160 struct in_addr *as4_aggregator_addr)
1161{
1162 int ignore_as4_path = 0;
1163 struct aspath *newpath;
1164 struct attr_extra *attre = attr->extra;
1165
1166 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1167 {
1168 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1169 * if given.
1170 * It is worth a warning though, because the peer really
1171 * should not send them
1172 */
1173 if (BGP_DEBUG(as4, AS4))
1174 {
1175 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1176 zlog_debug ("[AS4] %s %s AS4_PATH",
1177 peer->host, "AS4 capable peer, yet it sent");
1178
1179 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1180 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1181 peer->host, "AS4 capable peer, yet it sent");
1182 }
1183
1184 return 0;
1185 }
1186
1187 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1188 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1189 {
1190 /* Hu? This is not supposed to happen at all!
1191 * got as4_path and no aspath,
1192 * This should already
1193 * have been handled by 'well known attributes missing'
1194 * But... yeah, paranoia
1195 * Take this as a "malformed attribute"
1196 */
1197 zlog (peer->log, LOG_ERR,
1198 "%s BGP not AS4 capable peer sent AS4_PATH but"
1199 " no AS_PATH, cant do anything here", peer->host);
1200 bgp_notify_send (peer,
1201 BGP_NOTIFY_UPDATE_ERR,
1202 BGP_NOTIFY_UPDATE_MAL_ATTR);
1203 return -1;
1204 }
1205
1206 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1207 * because that may override AS4_PATH
1208 */
1209 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1210 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001211 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1212 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001213 assert (attre);
1214
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001215 /* received both.
1216 * if the as_number in aggregator is not AS_TRANS,
1217 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1218 * and the Aggregator shall be taken as
1219 * info on the aggregating node, and the AS_PATH
1220 * shall be taken as the AS_PATH
1221 * otherwise
1222 * the Aggregator shall be ignored and the
1223 * AS4_AGGREGATOR shall be taken as the
1224 * Aggregating node and the AS_PATH is to be
1225 * constructed "as in all other cases"
1226 */
1227 if ( attre->aggregator_as != BGP_AS_TRANS )
1228 {
1229 /* ignore */
1230 if ( BGP_DEBUG(as4, AS4))
1231 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1232 " send AGGREGATOR != AS_TRANS and"
1233 " AS4_AGGREGATOR, so ignore"
1234 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1235 ignore_as4_path = 1;
1236 }
1237 else
1238 {
1239 /* "New_aggregator shall be taken as aggregator" */
1240 attre->aggregator_as = as4_aggregator;
1241 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1242 }
1243 }
1244 else
1245 {
1246 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1247 * That is bogus - but reading the conditions
1248 * we have to handle AS4_AGGREGATOR as if it were
1249 * AGGREGATOR in that case
1250 */
1251 if ( BGP_DEBUG(as4, AS4))
1252 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1253 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1254 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001255 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001256 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1257 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1258 }
1259 }
1260
1261 /* need to reconcile NEW_AS_PATH and AS_PATH */
1262 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1263 {
1264 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1265 aspath_unintern (attr->aspath);
1266 attr->aspath = aspath_intern (newpath);
1267 }
1268 return 0;
1269}
1270
paul718e3742002-12-13 20:15:29 +00001271/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001272static int
paul718e3742002-12-13 20:15:29 +00001273bgp_attr_community (struct peer *peer, bgp_size_t length,
1274 struct attr *attr, u_char flag)
1275{
1276 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001277 {
1278 attr->community = NULL;
1279 return 0;
1280 }
Paul Jakmafc097162010-12-05 17:17:26 +00001281
1282 attr->community =
1283 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1284
1285 /* XXX: fix community_parse to use stream API and remove this */
1286 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001287
Paul Jakmafc097162010-12-05 17:17:26 +00001288 if (!attr->community)
1289 return -1;
1290
paul718e3742002-12-13 20:15:29 +00001291 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1292
1293 return 0;
1294}
1295
1296/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001297static int
paul718e3742002-12-13 20:15:29 +00001298bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienko5de17192011-09-30 15:08:54 +04001299 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001300{
Denis Ovsienko5de17192011-09-30 15:08:54 +04001301 bgp_size_t total;
1302
1303 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1304 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001305 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko5de17192011-09-30 15:08:54 +04001306 {
1307 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1308 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1309 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1310 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1311 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1312 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
1313 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1314 return -1;
1315 }
1316 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001317 if (length != 4)
1318 {
1319 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1320
1321 bgp_notify_send (peer,
1322 BGP_NOTIFY_UPDATE_ERR,
1323 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1324 return -1;
1325 }
1326
Paul Jakmafb982c22007-05-04 20:15:47 +00001327 (bgp_attr_extra_get (attr))->originator_id.s_addr
1328 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001329
1330 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1331
1332 return 0;
1333}
1334
1335/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001336static int
paul718e3742002-12-13 20:15:29 +00001337bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001338 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001339{
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001340 bgp_size_t total;
1341
1342 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1343 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001344 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001345 {
1346 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1347 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1348 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1349 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1350 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1351 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
1352 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1353 return -1;
1354 }
paul718e3742002-12-13 20:15:29 +00001355 /* Check length. */
1356 if (length % 4)
1357 {
1358 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1359
1360 bgp_notify_send (peer,
1361 BGP_NOTIFY_UPDATE_ERR,
1362 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1363 return -1;
1364 }
1365
Paul Jakmafb982c22007-05-04 20:15:47 +00001366 (bgp_attr_extra_get (attr))->cluster
1367 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001368
paul9985f832005-02-09 15:51:56 +00001369 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001370
1371 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1372
1373 return 0;
1374}
1375
1376/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001377int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001378bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1379 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001380{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001381 afi_t afi;
1382 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001383 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001384 size_t start;
paul718e3742002-12-13 20:15:29 +00001385 int ret;
1386 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001387 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001388 bgp_size_t total;
1389
1390 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1391 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001392 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001393 {
1394 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1395 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1396 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1397 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1398 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1399 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
1400 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1401 return -1;
1402 }
paul718e3742002-12-13 20:15:29 +00001403 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001404 s = BGP_INPUT(peer);
1405 start = stream_get_getp(s);
1406
1407 /* safe to read statically sized header? */
1408#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001409#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001410 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001411 {
1412 zlog_info ("%s: %s sent invalid length, %lu",
1413 __func__, peer->host, (unsigned long)length);
1414 return -1;
1415 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001416
paul718e3742002-12-13 20:15:29 +00001417 /* Load AFI, SAFI. */
1418 afi = stream_getw (s);
1419 safi = stream_getc (s);
1420
1421 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001422 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001423
Paul Jakma03292802008-06-07 20:37:10 +00001424 if (LEN_LEFT < attre->mp_nexthop_len)
1425 {
1426 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1427 __func__, peer->host, attre->mp_nexthop_len);
1428 return -1;
1429 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001430
paul718e3742002-12-13 20:15:29 +00001431 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001432 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001433 {
1434 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001435 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001436 /* Probably needed for RFC 2283 */
1437 if (attr->nexthop.s_addr == 0)
1438 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001439 break;
1440 case 12:
1441 {
1442 u_int32_t rd_high;
1443 u_int32_t rd_low;
1444
1445 rd_high = stream_getl (s);
1446 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001447 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001448 }
1449 break;
1450#ifdef HAVE_IPV6
1451 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001452 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001453 break;
1454 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 stream_get (&attre->mp_nexthop_global, s, 16);
1456 stream_get (&attre->mp_nexthop_local, s, 16);
1457 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001458 {
1459 char buf1[INET6_ADDRSTRLEN];
1460 char buf2[INET6_ADDRSTRLEN];
1461
1462 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001463 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 +00001464 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001465 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001466 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001467 buf2, INET6_ADDRSTRLEN));
1468
Paul Jakmafb982c22007-05-04 20:15:47 +00001469 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001470 }
1471 break;
1472#endif /* HAVE_IPV6 */
1473 default:
Paul Jakma03292802008-06-07 20:37:10 +00001474 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1475 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001476 return -1;
paul718e3742002-12-13 20:15:29 +00001477 }
1478
Paul Jakma03292802008-06-07 20:37:10 +00001479 if (!LEN_LEFT)
1480 {
1481 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1482 __func__, peer->host);
1483 return -1;
1484 }
paul718e3742002-12-13 20:15:29 +00001485
Paul Jakma6e4ab122007-04-10 19:36:48 +00001486 {
1487 u_char val;
1488 if ((val = stream_getc (s)))
1489 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1490 peer->host, val);
1491 }
1492
1493 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001494 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001495 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001496 {
1497 zlog_info ("%s: (%s) Failed to read NLRI",
1498 __func__, peer->host);
1499 return -1;
1500 }
paul718e3742002-12-13 20:15:29 +00001501
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001502 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001503 {
1504 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001505 if (ret < 0)
1506 {
1507 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1508 __func__, peer->host);
1509 return -1;
1510 }
paul718e3742002-12-13 20:15:29 +00001511 }
1512
1513 mp_update->afi = afi;
1514 mp_update->safi = safi;
1515 mp_update->nlri = stream_pnt (s);
1516 mp_update->length = nlri_len;
1517
paul9985f832005-02-09 15:51:56 +00001518 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001519
1520 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001521#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001522}
1523
1524/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001525int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001526bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1527 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001528 struct bgp_nlri *mp_withdraw)
1529{
1530 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001531 afi_t afi;
1532 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001533 u_int16_t withdraw_len;
1534 int ret;
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001535 bgp_size_t total;
1536
1537 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1538 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001539 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001540 {
1541 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1542 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1543 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1544 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1545 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1546 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
1547 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1548 return -1;
1549 }
paul718e3742002-12-13 20:15:29 +00001550
1551 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001552
1553#define BGP_MP_UNREACH_MIN_SIZE 3
1554 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1555 return -1;
1556
paul718e3742002-12-13 20:15:29 +00001557 afi = stream_getw (s);
1558 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001559
1560 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001561
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001562 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001563 {
1564 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1565 if (ret < 0)
1566 return -1;
1567 }
1568
1569 mp_withdraw->afi = afi;
1570 mp_withdraw->safi = safi;
1571 mp_withdraw->nlri = stream_pnt (s);
1572 mp_withdraw->length = withdraw_len;
1573
paul9985f832005-02-09 15:51:56 +00001574 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001575
1576 return 0;
1577}
1578
1579/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001580static int
paul718e3742002-12-13 20:15:29 +00001581bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1582 struct attr *attr, u_char flag)
1583{
1584 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001585 {
1586 if (attr->extra)
1587 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001588 /* Empty extcomm doesn't seem to be invalid per se */
1589 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001590 }
Paul Jakmafc097162010-12-05 17:17:26 +00001591
1592 (bgp_attr_extra_get (attr))->ecommunity =
1593 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1594 /* XXX: fix ecommunity_parse to use stream API */
1595 stream_forward_getp (peer->ibuf, length);
1596
1597 if (!attr->extra->ecommunity)
1598 return -1;
1599
paul718e3742002-12-13 20:15:29 +00001600 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1601
1602 return 0;
1603}
1604
1605/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001606static int
paul718e3742002-12-13 20:15:29 +00001607bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1608 u_char type, bgp_size_t length, u_char *startp)
1609{
1610 bgp_size_t total;
1611 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001612 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001613
hassof4184462005-02-01 20:13:16 +00001614 if (BGP_DEBUG (normal, NORMAL))
1615 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1616 peer->host, type, length);
1617
paul718e3742002-12-13 20:15:29 +00001618 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001619 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001620 "Unknown attribute type %d length %d is received", type, length);
1621
1622 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001623 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001624
1625 /* Adjest total length to include type and length. */
1626 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1627
1628 /* If any of the mandatory well-known attributes are not recognized,
1629 then the Error Subcode is set to Unrecognized Well-known
1630 Attribute. The Data field contains the unrecognized attribute
1631 (type, length and value). */
1632 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1633 {
1634 /* Adjust startp to do not include flag value. */
1635 bgp_notify_send_with_data (peer,
1636 BGP_NOTIFY_UPDATE_ERR,
1637 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1638 startp, total);
1639 return -1;
1640 }
1641
1642 /* Unrecognized non-transitive optional attributes must be quietly
1643 ignored and not passed along to other BGP peers. */
1644 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1645 return 0;
1646
1647 /* If a path with recognized transitive optional attribute is
1648 accepted and passed along to other BGP peers and the Partial bit
1649 in the Attribute Flags octet is set to 1 by some previous AS, it
1650 is not set back to 0 by the current AS. */
1651 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1652
1653 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001654 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001655 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001656
Paul Jakmafb982c22007-05-04 20:15:47 +00001657 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001658
1659 if (transit->val)
1660 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1661 transit->length + total);
1662 else
1663 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1664
1665 memcpy (transit->val + transit->length, startp, total);
1666 transit->length += total;
1667
1668 return 0;
1669}
1670
1671/* Read attribute of update packet. This function is called from
1672 bgp_update() in bgpd.c. */
1673int
1674bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1675 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1676{
1677 int ret;
1678 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001679 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001680 bgp_size_t length;
1681 u_char *startp, *endp;
1682 u_char *attr_endp;
1683 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001684 /* we need the as4_path only until we have synthesized the as_path with it */
1685 /* same goes for as4_aggregator */
1686 struct aspath *as4_path = NULL;
1687 as_t as4_aggregator = 0;
1688 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001689
1690 /* Initialize bitmap. */
1691 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1692
1693 /* End pointer of BGP attribute. */
1694 endp = BGP_INPUT_PNT (peer) + size;
1695
1696 /* Get attributes to the end of attribute length. */
1697 while (BGP_INPUT_PNT (peer) < endp)
1698 {
1699 /* Check remaining length check.*/
1700 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1701 {
gdtc29fdba2004-12-09 14:46:46 +00001702 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001703 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001704 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001705 peer->host,
1706 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001707
1708 bgp_notify_send (peer,
1709 BGP_NOTIFY_UPDATE_ERR,
1710 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1711 return -1;
1712 }
1713
1714 /* Fetch attribute flag and type. */
1715 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001716 /* "The lower-order four bits of the Attribute Flags octet are
1717 unused. They MUST be zero when sent and MUST be ignored when
1718 received." */
1719 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001720 type = stream_getc (BGP_INPUT (peer));
1721
Paul Jakma370b64a2007-12-22 16:49:52 +00001722 /* Check whether Extended-Length applies and is in bounds */
1723 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1724 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1725 {
1726 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001727 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001728 peer->host,
1729 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1730
1731 bgp_notify_send (peer,
1732 BGP_NOTIFY_UPDATE_ERR,
1733 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1734 return -1;
1735 }
1736
paul718e3742002-12-13 20:15:29 +00001737 /* Check extended attribue length bit. */
1738 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1739 length = stream_getw (BGP_INPUT (peer));
1740 else
1741 length = stream_getc (BGP_INPUT (peer));
1742
1743 /* If any attribute appears more than once in the UPDATE
1744 message, then the Error Subcode is set to Malformed Attribute
1745 List. */
1746
1747 if (CHECK_BITMAP (seen, type))
1748 {
1749 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001750 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001751 peer->host, type);
1752
1753 bgp_notify_send (peer,
1754 BGP_NOTIFY_UPDATE_ERR,
1755 BGP_NOTIFY_UPDATE_MAL_ATTR);
1756 return -1;
1757 }
1758
1759 /* Set type to bitmap to check duplicate attribute. `type' is
1760 unsigned char so it never overflow bitmap range. */
1761
1762 SET_BITMAP (seen, type);
1763
1764 /* Overflow check. */
1765 attr_endp = BGP_INPUT_PNT (peer) + length;
1766
1767 if (attr_endp > endp)
1768 {
1769 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001770 "%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 +00001771 bgp_notify_send (peer,
1772 BGP_NOTIFY_UPDATE_ERR,
1773 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1774 return -1;
1775 }
1776
1777 /* OK check attribute and store it's value. */
1778 switch (type)
1779 {
1780 case BGP_ATTR_ORIGIN:
1781 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1782 break;
1783 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001784 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1785 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001786 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001787 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001788 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1789 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001790 break;
paul718e3742002-12-13 20:15:29 +00001791 case BGP_ATTR_NEXT_HOP:
1792 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1793 break;
1794 case BGP_ATTR_MULTI_EXIT_DISC:
1795 ret = bgp_attr_med (peer, length, attr, flag, startp);
1796 break;
1797 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001798 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001799 break;
1800 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001801 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001802 break;
1803 case BGP_ATTR_AGGREGATOR:
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001804 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001805 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001806 case BGP_ATTR_AS4_AGGREGATOR:
1807 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1808 break;
paul718e3742002-12-13 20:15:29 +00001809 case BGP_ATTR_COMMUNITIES:
1810 ret = bgp_attr_community (peer, length, attr, flag);
1811 break;
1812 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienko5de17192011-09-30 15:08:54 +04001813 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001814 break;
1815 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001816 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001817 break;
1818 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001819 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001820 break;
1821 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001822 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001823 break;
1824 case BGP_ATTR_EXT_COMMUNITIES:
1825 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1826 break;
1827 default:
1828 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1829 break;
1830 }
1831
1832 /* If error occured immediately return to the caller. */
1833 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001834 {
1835 zlog (peer->log, LOG_WARNING,
1836 "%s: Attribute %s, parse error",
1837 peer->host,
1838 LOOKUP (attr_str, type));
1839 bgp_notify_send (peer,
1840 BGP_NOTIFY_UPDATE_ERR,
1841 BGP_NOTIFY_UPDATE_MAL_ATTR);
1842 return ret;
1843 }
paul718e3742002-12-13 20:15:29 +00001844
1845 /* Check the fetched length. */
1846 if (BGP_INPUT_PNT (peer) != attr_endp)
1847 {
1848 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001849 "%s: BGP attribute %s, fetch error",
1850 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001851 bgp_notify_send (peer,
1852 BGP_NOTIFY_UPDATE_ERR,
1853 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1854 return -1;
1855 }
1856 }
1857
1858 /* Check final read pointer is same as end pointer. */
1859 if (BGP_INPUT_PNT (peer) != endp)
1860 {
1861 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001862 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001863 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001864 bgp_notify_send (peer,
1865 BGP_NOTIFY_UPDATE_ERR,
1866 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1867 return -1;
1868 }
1869
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001870 /*
1871 * At this place we can see whether we got AS4_PATH and/or
1872 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1873 * We can not do this before we've read all attributes because
1874 * the as4 handling does not say whether AS4_PATH has to be sent
1875 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1876 * in relationship to AGGREGATOR.
1877 * So, to be defensive, we are not relying on any order and read
1878 * all attributes first, including these 32bit ones, and now,
1879 * afterwards, we look what and if something is to be done for as4.
1880 */
1881 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1882 as4_aggregator, &as4_aggregator_addr))
1883 return -1;
1884
1885 /* At this stage, we have done all fiddling with as4, and the
1886 * resulting info is in attr->aggregator resp. attr->aspath
1887 * so we can chuck as4_aggregator and as4_path alltogether in
1888 * order to save memory
1889 */
1890 if ( as4_path )
1891 {
1892 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1893 as4_path = NULL;
1894 /* The flag that we got this is still there, but that does not
1895 * do any trouble
1896 */
1897 }
1898 /*
1899 * The "rest" of the code does nothing with as4_aggregator.
1900 * there is no memory attached specifically which is not part
1901 * of the attr.
1902 * so ignoring just means do nothing.
1903 */
1904 /*
1905 * Finally do the checks on the aspath we did not do yet
1906 * because we waited for a potentially synthesized aspath.
1907 */
1908 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1909 {
1910 ret = bgp_attr_aspath_check( peer, attr );
1911 if ( ret < 0 )
1912 return ret;
1913 }
1914
paul718e3742002-12-13 20:15:29 +00001915 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001916 if (attr->extra && attr->extra->transit)
1917 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001918
1919 return 0;
1920}
1921
1922/* Well-known attribute check. */
1923int
1924bgp_attr_check (struct peer *peer, struct attr *attr)
1925{
1926 u_char type = 0;
1927
1928 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1929 type = BGP_ATTR_ORIGIN;
1930
1931 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1932 type = BGP_ATTR_AS_PATH;
1933
1934 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1935 type = BGP_ATTR_NEXT_HOP;
1936
1937 if (peer_sort (peer) == BGP_PEER_IBGP
1938 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1939 type = BGP_ATTR_LOCAL_PREF;
1940
1941 if (type)
1942 {
1943 zlog (peer->log, LOG_WARNING,
1944 "%s Missing well-known attribute %d.",
1945 peer->host, type);
1946 bgp_notify_send_with_data (peer,
1947 BGP_NOTIFY_UPDATE_ERR,
1948 BGP_NOTIFY_UPDATE_MISS_ATTR,
1949 &type, 1);
1950 return -1;
1951 }
1952 return 0;
1953}
1954
1955int stream_put_prefix (struct stream *, struct prefix *);
1956
1957/* Make attribute packet. */
1958bgp_size_t
1959bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1960 struct stream *s, struct attr *attr, struct prefix *p,
1961 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001962 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001963{
paulfe69a502005-09-10 16:55:02 +00001964 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001965 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001966 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001967 int send_as4_path = 0;
1968 int send_as4_aggregator = 0;
1969 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001970
1971 if (! bgp)
1972 bgp = bgp_get_default ();
1973
1974 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001975 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001976
1977 /* Origin attribute. */
1978 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1979 stream_putc (s, BGP_ATTR_ORIGIN);
1980 stream_putc (s, 1);
1981 stream_putc (s, attr->origin);
1982
1983 /* AS path attribute. */
1984
1985 /* If remote-peer is EBGP */
1986 if (peer_sort (peer) == BGP_PEER_EBGP
1987 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001988 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001989 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001990 {
1991 aspath = aspath_dup (attr->aspath);
1992
1993 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1994 {
1995 /* Strip the confed info, and then stuff our path CONFED_ID
1996 on the front */
1997 aspath = aspath_delete_confed_seq (aspath);
1998 aspath = aspath_add_seq (aspath, bgp->confed_id);
1999 }
2000 else
2001 {
2002 aspath = aspath_add_seq (aspath, peer->local_as);
2003 if (peer->change_local_as)
2004 aspath = aspath_add_seq (aspath, peer->change_local_as);
2005 }
2006 }
2007 else if (peer_sort (peer) == BGP_PEER_CONFED)
2008 {
2009 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2010 aspath = aspath_dup (attr->aspath);
2011 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2012 }
2013 else
2014 aspath = attr->aspath;
2015
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002016 /* If peer is not AS4 capable, then:
2017 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2018 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2019 * types are in it (i.e. exclude them if they are there)
2020 * AND do this only if there is at least one asnum > 65535 in the path!
2021 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2022 * all ASnums > 65535 to BGP_AS_TRANS
2023 */
paul718e3742002-12-13 20:15:29 +00002024
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002025 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2026 stream_putc (s, BGP_ATTR_AS_PATH);
2027 aspath_sizep = stream_get_endp (s);
2028 stream_putw (s, 0);
2029 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2030
2031 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2032 * in the path
2033 */
2034 if (!use32bit && aspath_has_as4 (aspath))
2035 send_as4_path = 1; /* we'll do this later, at the correct place */
2036
paul718e3742002-12-13 20:15:29 +00002037 /* Nexthop attribute. */
2038 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2039 {
2040 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2041 stream_putc (s, BGP_ATTR_NEXT_HOP);
2042 stream_putc (s, 4);
2043 if (safi == SAFI_MPLS_VPN)
2044 {
2045 if (attr->nexthop.s_addr == 0)
2046 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2047 else
2048 stream_put_ipv4 (s, attr->nexthop.s_addr);
2049 }
2050 else
2051 stream_put_ipv4 (s, attr->nexthop.s_addr);
2052 }
2053
2054 /* MED attribute. */
2055 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2056 {
2057 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2058 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2059 stream_putc (s, 4);
2060 stream_putl (s, attr->med);
2061 }
2062
2063 /* Local preference. */
2064 if (peer_sort (peer) == BGP_PEER_IBGP ||
2065 peer_sort (peer) == BGP_PEER_CONFED)
2066 {
2067 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2068 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2069 stream_putc (s, 4);
2070 stream_putl (s, attr->local_pref);
2071 }
2072
2073 /* Atomic aggregate. */
2074 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2075 {
2076 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2077 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2078 stream_putc (s, 0);
2079 }
2080
2081 /* Aggregator. */
2082 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2083 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002084 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002085
2086 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002087 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2088 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002089
2090 if (use32bit)
2091 {
2092 /* AS4 capable peer */
2093 stream_putc (s, 8);
2094 stream_putl (s, attr->extra->aggregator_as);
2095 }
2096 else
2097 {
2098 /* 2-byte AS peer */
2099 stream_putc (s, 6);
2100
2101 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2102 if ( attr->extra->aggregator_as > 65535 )
2103 {
2104 stream_putw (s, BGP_AS_TRANS);
2105
2106 /* we have to send AS4_AGGREGATOR, too.
2107 * we'll do that later in order to send attributes in ascending
2108 * order.
2109 */
2110 send_as4_aggregator = 1;
2111 }
2112 else
2113 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2114 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002115 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002116 }
2117
2118 /* Community attribute. */
2119 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2120 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2121 {
2122 if (attr->community->size * 4 > 255)
2123 {
2124 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2125 stream_putc (s, BGP_ATTR_COMMUNITIES);
2126 stream_putw (s, attr->community->size * 4);
2127 }
2128 else
2129 {
2130 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2131 stream_putc (s, BGP_ATTR_COMMUNITIES);
2132 stream_putc (s, attr->community->size * 4);
2133 }
2134 stream_put (s, attr->community->val, attr->community->size * 4);
2135 }
2136
2137 /* Route Reflector. */
2138 if (peer_sort (peer) == BGP_PEER_IBGP
2139 && from
2140 && peer_sort (from) == BGP_PEER_IBGP)
2141 {
2142 /* Originator ID. */
2143 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2144 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2145 stream_putc (s, 4);
2146
2147 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002148 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002149 else
2150 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002151
2152 /* Cluster list. */
2153 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2154 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2155
Paul Jakma9eda90c2007-08-30 13:36:17 +00002156 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002157 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002158 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002159 /* If this peer configuration's parent BGP has cluster_id. */
2160 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2161 stream_put_in_addr (s, &bgp->cluster_id);
2162 else
2163 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002164 stream_put (s, attr->extra->cluster->list,
2165 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002166 }
2167 else
2168 {
2169 stream_putc (s, 4);
2170 /* If this peer configuration's parent BGP has cluster_id. */
2171 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2172 stream_put_in_addr (s, &bgp->cluster_id);
2173 else
2174 stream_put_in_addr (s, &bgp->router_id);
2175 }
2176 }
2177
2178#ifdef HAVE_IPV6
2179 /* If p is IPv6 address put it into attribute. */
2180 if (p->family == AF_INET6)
2181 {
2182 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002183 struct attr_extra *attre = attr->extra;
2184
2185 assert (attr->extra);
2186
paul718e3742002-12-13 20:15:29 +00002187 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2188 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002189 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002190 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002191 stream_putw (s, AFI_IP6); /* AFI */
2192 stream_putc (s, safi); /* SAFI */
2193
Paul Jakmafb982c22007-05-04 20:15:47 +00002194 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002195
Paul Jakmafb982c22007-05-04 20:15:47 +00002196 if (attre->mp_nexthop_len == 16)
2197 stream_put (s, &attre->mp_nexthop_global, 16);
2198 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002199 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002200 stream_put (s, &attre->mp_nexthop_global, 16);
2201 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002202 }
2203
2204 /* SNPA */
2205 stream_putc (s, 0);
2206
paul718e3742002-12-13 20:15:29 +00002207 /* Prefix write. */
2208 stream_put_prefix (s, p);
2209
2210 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002211 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002212 }
2213#endif /* HAVE_IPV6 */
2214
2215 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2216 {
2217 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002218
2219 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2220 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002221 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002222 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002223 stream_putw (s, AFI_IP); /* AFI */
2224 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2225
2226 stream_putc (s, 4);
2227 stream_put_ipv4 (s, attr->nexthop.s_addr);
2228
2229 /* SNPA */
2230 stream_putc (s, 0);
2231
paul718e3742002-12-13 20:15:29 +00002232 /* Prefix write. */
2233 stream_put_prefix (s, p);
2234
2235 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002236 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002237 }
2238
2239 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2240 {
2241 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002242
2243 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2244 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002245 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002246 stream_putc (s, 0); /* Length of this attribute. */
2247 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002248 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002249
2250 stream_putc (s, 12);
2251 stream_putl (s, 0);
2252 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002253 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002254
2255 /* SNPA */
2256 stream_putc (s, 0);
2257
paul718e3742002-12-13 20:15:29 +00002258 /* Tag, RD, Prefix write. */
2259 stream_putc (s, p->prefixlen + 88);
2260 stream_put (s, tag, 3);
2261 stream_put (s, prd->val, 8);
2262 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2263
2264 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002265 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002266 }
2267
2268 /* Extended Communities attribute. */
2269 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2270 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2271 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002272 struct attr_extra *attre = attr->extra;
2273
2274 assert (attre);
2275
2276 if (peer_sort (peer) == BGP_PEER_IBGP
2277 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002278 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002279 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002280 {
2281 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2282 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002283 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002284 }
2285 else
2286 {
2287 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2288 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002289 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002290 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002291 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002292 }
2293 else
2294 {
paul5228ad22004-06-04 17:58:18 +00002295 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002296 int tbit;
2297 int ecom_tr_size = 0;
2298 int i;
2299
Paul Jakmafb982c22007-05-04 20:15:47 +00002300 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002301 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002302 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002303 tbit = *pnt;
2304
2305 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2306 continue;
2307
2308 ecom_tr_size++;
2309 }
2310
2311 if (ecom_tr_size)
2312 {
2313 if (ecom_tr_size * 8 > 255)
2314 {
2315 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2316 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2317 stream_putw (s, ecom_tr_size * 8);
2318 }
2319 else
2320 {
2321 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2322 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2323 stream_putc (s, ecom_tr_size * 8);
2324 }
2325
Paul Jakmafb982c22007-05-04 20:15:47 +00002326 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002327 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002328 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002329 tbit = *pnt;
2330
2331 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2332 continue;
2333
2334 stream_put (s, pnt, 8);
2335 }
2336 }
paul718e3742002-12-13 20:15:29 +00002337 }
paul718e3742002-12-13 20:15:29 +00002338 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002339
2340 if ( send_as4_path )
2341 {
2342 /* If the peer is NOT As4 capable, AND */
2343 /* there are ASnums > 65535 in path THEN
2344 * give out AS4_PATH */
2345
2346 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2347 * path segments!
2348 * Hm, I wonder... confederation things *should* only be at
2349 * the beginning of an aspath, right? Then we should use
2350 * aspath_delete_confed_seq for this, because it is already
2351 * there! (JK)
2352 * Folks, talk to me: what is reasonable here!?
2353 */
2354 aspath = aspath_delete_confed_seq (aspath);
2355
2356 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2357 stream_putc (s, BGP_ATTR_AS4_PATH);
2358 aspath_sizep = stream_get_endp (s);
2359 stream_putw (s, 0);
2360 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2361 }
2362
2363 if (aspath != attr->aspath)
2364 aspath_free (aspath);
2365
2366 if ( send_as4_aggregator )
2367 {
2368 assert (attr->extra);
2369
2370 /* send AS4_AGGREGATOR, at this place */
2371 /* this section of code moved here in order to ensure the correct
2372 * *ascending* order of attributes
2373 */
2374 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2375 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2376 stream_putc (s, 8);
2377 stream_putl (s, attr->extra->aggregator_as);
2378 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2379 }
Paul Jakma41367172007-08-06 15:24:51 +00002380
paul718e3742002-12-13 20:15:29 +00002381 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002382 if (attr->extra && attr->extra->transit)
2383 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002384
2385 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002386 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002387}
2388
2389bgp_size_t
2390bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2391 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002392 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002393{
2394 unsigned long cp;
2395 unsigned long attrlen_pnt;
2396 bgp_size_t size;
2397
paul9985f832005-02-09 15:51:56 +00002398 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002399
2400 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2401 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2402
paul9985f832005-02-09 15:51:56 +00002403 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002404 stream_putc (s, 0); /* Length of this attribute. */
2405
2406 stream_putw (s, family2afi (p->family));
2407
2408 if (safi == SAFI_MPLS_VPN)
2409 {
2410 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002411 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002412
2413 /* prefix. */
2414 stream_putc (s, p->prefixlen + 88);
2415 stream_put (s, tag, 3);
2416 stream_put (s, prd->val, 8);
2417 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2418 }
2419 else
2420 {
2421 /* SAFI */
2422 stream_putc (s, safi);
2423
2424 /* prefix */
2425 stream_put_prefix (s, p);
2426 }
2427
2428 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002429 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002430 stream_putc_at (s, attrlen_pnt, size);
2431
paul9985f832005-02-09 15:51:56 +00002432 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002433}
2434
2435/* Initialization of attribute. */
2436void
paulfe69a502005-09-10 16:55:02 +00002437bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002438{
paul718e3742002-12-13 20:15:29 +00002439 aspath_init ();
2440 attrhash_init ();
2441 community_init ();
2442 ecommunity_init ();
2443 cluster_init ();
2444 transit_init ();
2445}
2446
Chris Caputo228da422009-07-18 05:44:03 +00002447void
2448bgp_attr_finish (void)
2449{
2450 aspath_finish ();
2451 attrhash_finish ();
2452 community_finish ();
2453 ecommunity_finish ();
2454 cluster_finish ();
2455 transit_finish ();
2456}
2457
paul718e3742002-12-13 20:15:29 +00002458/* Make attribute packet. */
2459void
paula3845922003-10-18 01:30:50 +00002460bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2461 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002462{
2463 unsigned long cp;
2464 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002465 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002466 struct aspath *aspath;
2467
2468 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002469 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002470
2471 /* Place holder of length. */
2472 stream_putw (s, 0);
2473
2474 /* Origin attribute. */
2475 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2476 stream_putc (s, BGP_ATTR_ORIGIN);
2477 stream_putc (s, 1);
2478 stream_putc (s, attr->origin);
2479
2480 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002481
2482 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2483 stream_putc (s, BGP_ATTR_AS_PATH);
2484 aspath_lenp = stream_get_endp (s);
2485 stream_putw (s, 0);
2486
2487 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002488
2489 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002490 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2491 if(prefix != NULL
2492#ifdef HAVE_IPV6
2493 && prefix->family != AF_INET6
2494#endif /* HAVE_IPV6 */
2495 )
2496 {
2497 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2498 stream_putc (s, BGP_ATTR_NEXT_HOP);
2499 stream_putc (s, 4);
2500 stream_put_ipv4 (s, attr->nexthop.s_addr);
2501 }
paul718e3742002-12-13 20:15:29 +00002502
2503 /* MED attribute. */
2504 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2505 {
2506 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2507 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2508 stream_putc (s, 4);
2509 stream_putl (s, attr->med);
2510 }
2511
2512 /* Local preference. */
2513 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2514 {
2515 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2516 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2517 stream_putc (s, 4);
2518 stream_putl (s, attr->local_pref);
2519 }
2520
2521 /* Atomic aggregate. */
2522 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2523 {
2524 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2525 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2526 stream_putc (s, 0);
2527 }
2528
2529 /* Aggregator. */
2530 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2531 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002532 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002533 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2534 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002535 stream_putc (s, 8);
2536 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002537 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002538 }
2539
2540 /* Community attribute. */
2541 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2542 {
2543 if (attr->community->size * 4 > 255)
2544 {
2545 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2546 stream_putc (s, BGP_ATTR_COMMUNITIES);
2547 stream_putw (s, attr->community->size * 4);
2548 }
2549 else
2550 {
2551 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2552 stream_putc (s, BGP_ATTR_COMMUNITIES);
2553 stream_putc (s, attr->community->size * 4);
2554 }
2555 stream_put (s, attr->community->val, attr->community->size * 4);
2556 }
2557
paula3845922003-10-18 01:30:50 +00002558#ifdef HAVE_IPV6
2559 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002560 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2561 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002562 {
2563 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002564 struct attr_extra *attre = attr->extra;
2565
paula3845922003-10-18 01:30:50 +00002566 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2567 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002568 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002569
2570 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002571 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002572 stream_putw(s, AFI_IP6); /* AFI */
2573 stream_putc(s, SAFI_UNICAST); /* SAFI */
2574
2575 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002576 stream_putc(s, attre->mp_nexthop_len);
2577 stream_put(s, &attre->mp_nexthop_global, 16);
2578 if (attre->mp_nexthop_len == 32)
2579 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002580
2581 /* SNPA */
2582 stream_putc(s, 0);
2583
2584 /* Prefix */
2585 stream_put_prefix(s, prefix);
2586
2587 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002588 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002589 }
2590#endif /* HAVE_IPV6 */
2591
paul718e3742002-12-13 20:15:29 +00002592 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002593 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002594 stream_putw_at (s, cp, len);
2595}