blob: 7974477b48a2bf33c5f9e6129885a9b6f8c34d35 [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" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { 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 Ovsienkoe531d4a2011-09-24 13:20:43 +0400715 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +0000716 {
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400717 zlog (peer->log, LOG_ERR,
718 "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
719 bgp_notify_send_with_data (peer,
720 BGP_NOTIFY_UPDATE_ERR,
721 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
722 startp, total);
723 return -1;
724 }
725 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
726 {
727 zlog (peer->log, LOG_ERR,
728 "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
729 bgp_notify_send_with_data (peer,
730 BGP_NOTIFY_UPDATE_ERR,
731 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
732 startp, total);
733 return -1;
734 }
735 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
736 {
737 zlog (peer->log, LOG_ERR,
738 "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
739 bgp_notify_send_with_data (peer,
740 BGP_NOTIFY_UPDATE_ERR,
paul718e3742002-12-13 20:15:29 +0000741 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
742 startp, total);
743 return -1;
744 }
745
746 /* If any recognized attribute has Attribute Length that conflicts
747 with the expected length (based on the attribute type code), then
748 the Error Subcode is set to Attribute Length Error. The Data
749 field contains the erroneous attribute (type, length and
750 value). */
751 if (length != 1)
752 {
753 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
754 length);
755 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
756 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
757 startp, total);
758 return -1;
759 }
760
761 /* Fetch origin attribute. */
762 attr->origin = stream_getc (BGP_INPUT (peer));
763
764 /* If the ORIGIN attribute has an undefined value, then the Error
765 Subcode is set to Invalid Origin Attribute. The Data field
766 contains the unrecognized attribute (type, length and value). */
767 if ((attr->origin != BGP_ORIGIN_IGP)
768 && (attr->origin != BGP_ORIGIN_EGP)
769 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
770 {
771 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
772 attr->origin);
773
774 bgp_notify_send_with_data (peer,
775 BGP_NOTIFY_UPDATE_ERR,
776 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
777 startp, total);
778 return -1;
779 }
780
781 /* Set oring attribute flag. */
782 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
783
784 return 0;
785}
Chris Hallcddb8112010-08-09 22:31:37 +0400786/* Parse AS path information. This function is wrapper of aspath_parse.
787 *
788 * Parses AS_PATH or AS4_PATH.
789 *
790 * Returns: if valid: address of struct aspath in the hash of known aspaths,
791 * with reference count incremented.
792 * else: NULL
793 *
794 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
795 * have segments == NULL and str == zero length string (unique).
796 */
797static struct aspath *
paul718e3742002-12-13 20:15:29 +0000798bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400799 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000800{
Chris Hallcddb8112010-08-09 22:31:37 +0400801 u_char require ;
802 struct aspath *asp ;
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400803 bgp_size_t total;
804
805 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000806
Chris Hallcddb8112010-08-09 22:31:37 +0400807 /* Check the attribute flags */
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400808 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
809 {
810 zlog (peer->log, LOG_ERR,
811 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
812 bgp_notify_send_with_data (peer,
813 BGP_NOTIFY_UPDATE_ERR,
814 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
815 startp, total);
816 return NULL;
817 }
818
Chris Hallcddb8112010-08-09 22:31:37 +0400819 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
820 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000821
Chris Hallcddb8112010-08-09 22:31:37 +0400822 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000823 {
Chris Hallcddb8112010-08-09 22:31:37 +0400824 const char* path_type ;
Chris Hallcddb8112010-08-09 22:31:37 +0400825
826 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
827
828 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000829 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400830 "%s attribute flag isn't transitive %d", path_type, flag) ;
831
832 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
833 zlog (peer->log, LOG_ERR,
834 "%s attribute flag must %sbe optional %d", path_type,
835 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
836
paul718e3742002-12-13 20:15:29 +0000837 bgp_notify_send_with_data (peer,
838 BGP_NOTIFY_UPDATE_ERR,
839 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
840 startp, total);
paul718e3742002-12-13 20:15:29 +0000841
Chris Hallcddb8112010-08-09 22:31:37 +0400842 return NULL ;
843 } ;
844
845 /* Parse the AS_PATH/AS4_PATH body.
846 *
847 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
848 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000849 */
Chris Hallcddb8112010-08-09 22:31:37 +0400850 asp = aspath_parse (peer->ibuf, length,
851 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000852
Chris Hallcddb8112010-08-09 22:31:37 +0400853 if (asp != NULL)
854 {
855 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
856 : BGP_ATTR_AS_PATH) ;
857 }
858 else
paul718e3742002-12-13 20:15:29 +0000859 {
860 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400861
862 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000863 bgp_notify_send (peer,
864 BGP_NOTIFY_UPDATE_ERR,
865 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400866 } ;
paul718e3742002-12-13 20:15:29 +0000867
Chris Hallcddb8112010-08-09 22:31:37 +0400868 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000869}
870
871static int bgp_attr_aspath_check( struct peer *peer,
872 struct attr *attr)
873{
874 /* These checks were part of bgp_attr_aspath, but with
875 * as4 we should to check aspath things when
876 * aspath synthesizing with as4_path has already taken place.
877 * Otherwise we check ASPATH and use the synthesized thing, and that is
878 * not right.
879 * So do the checks later, i.e. here
880 */
881 struct bgp *bgp = peer->bgp;
882 struct aspath *aspath;
883
paul718e3742002-12-13 20:15:29 +0000884 bgp = peer->bgp;
885
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300886 /* Confederation sanity check. */
887 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
888 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
889 {
890 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
891 bgp_notify_send (peer,
892 BGP_NOTIFY_UPDATE_ERR,
893 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
894 return -1;
895 }
896
paul718e3742002-12-13 20:15:29 +0000897 /* First AS check for EBGP. */
898 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
899 {
900 if (peer_sort (peer) == BGP_PEER_EBGP
901 && ! aspath_firstas_check (attr->aspath, peer->as))
902 {
903 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400904 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000905 bgp_notify_send (peer,
906 BGP_NOTIFY_UPDATE_ERR,
907 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
908 return -1;
909 }
910 }
911
912 /* local-as prepend */
913 if (peer->change_local_as &&
914 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
915 {
916 aspath = aspath_dup (attr->aspath);
917 aspath = aspath_add_seq (aspath, peer->change_local_as);
918 aspath_unintern (attr->aspath);
919 attr->aspath = aspath_intern (aspath);
920 }
921
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000922 return 0;
923
924}
925
paul718e3742002-12-13 20:15:29 +0000926/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000927static int
paul718e3742002-12-13 20:15:29 +0000928bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
929 struct attr *attr, u_char flag, u_char *startp)
930{
931 bgp_size_t total;
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400932 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000933
934 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
935
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400936 /* Flags check. */
937 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +0000938 {
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400939 zlog (peer->log, LOG_ERR,
940 "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
941 bgp_notify_send_with_data (peer,
942 BGP_NOTIFY_UPDATE_ERR,
943 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
944 startp, total);
945 return -1;
946 }
947 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
948 {
949 zlog (peer->log, LOG_ERR,
950 "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
951 bgp_notify_send_with_data (peer,
952 BGP_NOTIFY_UPDATE_ERR,
953 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
954 startp, total);
955 return -1;
956 }
957 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
958 {
959 zlog (peer->log, LOG_ERR,
960 "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
961 bgp_notify_send_with_data (peer,
962 BGP_NOTIFY_UPDATE_ERR,
paul718e3742002-12-13 20:15:29 +0000963 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
964 startp, total);
965 return -1;
966 }
967
968 /* Check nexthop attribute length. */
969 if (length != 4)
970 {
971 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
972 length);
973
974 bgp_notify_send_with_data (peer,
975 BGP_NOTIFY_UPDATE_ERR,
976 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
977 startp, total);
978 return -1;
979 }
980
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400981 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
982 attribute must result in a NOTIFICATION message (this is implemented below).
983 At the same time, semantically incorrect NEXT_HOP is more likely to be just
984 logged locally (this is implemented somewhere else). The UPDATE message
985 gets ignored in any of these cases. */
986 nexthop_n = stream_get_ipv4 (peer->ibuf);
987 nexthop_h = ntohl (nexthop_n);
988 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
989 {
990 char buf[INET_ADDRSTRLEN];
991 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
992 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
993 bgp_notify_send_with_data (peer,
994 BGP_NOTIFY_UPDATE_ERR,
995 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
996 startp, total);
997 return -1;
998 }
999
1000 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001001 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1002
1003 return 0;
1004}
1005
1006/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +00001007static int
paul718e3742002-12-13 20:15:29 +00001008bgp_attr_med (struct peer *peer, bgp_size_t length,
1009 struct attr *attr, u_char flag, u_char *startp)
1010{
1011 bgp_size_t total;
1012
1013 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1014
Denis Ovsienko7d25f182011-09-20 10:54:25 +04001015 /* Flag checks. */
1016 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1017 {
1018 zlog (peer->log, LOG_ERR,
1019 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1020 bgp_notify_send_with_data (peer,
1021 BGP_NOTIFY_UPDATE_ERR,
1022 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1023 startp, total);
1024 return -1;
1025 }
1026 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1027 {
1028 zlog (peer->log, LOG_ERR,
1029 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1030 bgp_notify_send_with_data (peer,
1031 BGP_NOTIFY_UPDATE_ERR,
1032 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1033 startp, total);
1034 return -1;
1035 }
1036 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1037 {
1038 zlog (peer->log, LOG_ERR,
1039 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
1040 bgp_notify_send_with_data (peer,
1041 BGP_NOTIFY_UPDATE_ERR,
1042 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1043 startp, total);
1044 return -1;
1045 }
1046
paul718e3742002-12-13 20:15:29 +00001047 /* Length check. */
1048 if (length != 4)
1049 {
1050 zlog (peer->log, LOG_ERR,
1051 "MED attribute length isn't four [%d]", length);
1052
1053 bgp_notify_send_with_data (peer,
1054 BGP_NOTIFY_UPDATE_ERR,
1055 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1056 startp, total);
1057 return -1;
1058 }
1059
1060 attr->med = stream_getl (peer->ibuf);
1061
1062 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1063
1064 return 0;
1065}
1066
1067/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001068static int
paul718e3742002-12-13 20:15:29 +00001069bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001070 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001071{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001072 bgp_size_t total;
1073
1074 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1075 /* Flag checks. */
1076 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1077 {
1078 zlog (peer->log, LOG_ERR,
1079 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1080 bgp_notify_send_with_data (peer,
1081 BGP_NOTIFY_UPDATE_ERR,
1082 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1083 startp, total);
1084 return -1;
1085 }
1086 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1087 {
1088 zlog (peer->log, LOG_ERR,
1089 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1090 bgp_notify_send_with_data (peer,
1091 BGP_NOTIFY_UPDATE_ERR,
1092 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1093 startp, total);
1094 return -1;
1095 }
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +04001096 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1097 {
1098 zlog (peer->log, LOG_ERR,
1099 "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1100 bgp_notify_send_with_data (peer,
1101 BGP_NOTIFY_UPDATE_ERR,
1102 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1103 startp, total);
1104 return -1;
1105 }
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001106
paul718e3742002-12-13 20:15:29 +00001107 /* If it is contained in an UPDATE message that is received from an
1108 external peer, then this attribute MUST be ignored by the
1109 receiving speaker. */
1110 if (peer_sort (peer) == BGP_PEER_EBGP)
1111 {
paul9985f832005-02-09 15:51:56 +00001112 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001113 return 0;
1114 }
1115
1116 if (length == 4)
1117 attr->local_pref = stream_getl (peer->ibuf);
1118 else
1119 attr->local_pref = 0;
1120
1121 /* Set atomic aggregate flag. */
1122 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1123
1124 return 0;
1125}
1126
1127/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001128static int
paul718e3742002-12-13 20:15:29 +00001129bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001130 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001131{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001132 bgp_size_t total;
1133
1134 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1135 /* Flag checks. */
1136 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1137 {
1138 zlog (peer->log, LOG_ERR,
1139 "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1140 bgp_notify_send_with_data (peer,
1141 BGP_NOTIFY_UPDATE_ERR,
1142 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1143 startp, total);
1144 return -1;
1145 }
1146 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1147 {
1148 zlog (peer->log, LOG_ERR,
1149 "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1150 bgp_notify_send_with_data (peer,
1151 BGP_NOTIFY_UPDATE_ERR,
1152 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1153 startp, total);
1154 return -1;
1155 }
1156 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1157 {
1158 zlog (peer->log, LOG_ERR,
1159 "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1160 bgp_notify_send_with_data (peer,
1161 BGP_NOTIFY_UPDATE_ERR,
1162 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1163 startp, total);
1164 return -1;
1165 }
1166
1167 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001168 if (length != 0)
1169 {
1170 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1171
1172 bgp_notify_send (peer,
1173 BGP_NOTIFY_UPDATE_ERR,
1174 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1175 return -1;
1176 }
1177
1178 /* Set atomic aggregate flag. */
1179 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1180
1181 return 0;
1182}
1183
1184/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001185static int
paul718e3742002-12-13 20:15:29 +00001186bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1187 struct attr *attr, u_char flag)
1188{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001189 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001190 struct attr_extra *attre = bgp_attr_extra_get (attr);
1191
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001192 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1193 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1194 wantedlen = 8;
1195
1196 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001197 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001198 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001199
1200 bgp_notify_send (peer,
1201 BGP_NOTIFY_UPDATE_ERR,
1202 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1203 return -1;
1204 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205
1206 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1207 attre->aggregator_as = stream_getl (peer->ibuf);
1208 else
1209 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001210 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001211
1212 /* Set atomic aggregate flag. */
1213 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1214
1215 return 0;
1216}
1217
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001218/* New Aggregator attribute */
1219static int
1220bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1221 struct attr *attr, as_t *as4_aggregator_as,
1222 struct in_addr *as4_aggregator_addr)
1223{
1224 if (length != 8)
1225 {
1226 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1227
1228 bgp_notify_send (peer,
1229 BGP_NOTIFY_UPDATE_ERR,
1230 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1231 return -1;
1232 }
1233 *as4_aggregator_as = stream_getl (peer->ibuf);
1234 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1235
1236 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1237
1238 return 0;
1239}
1240
1241/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1242 */
1243static int
1244bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1245 struct aspath *as4_path, as_t as4_aggregator,
1246 struct in_addr *as4_aggregator_addr)
1247{
1248 int ignore_as4_path = 0;
1249 struct aspath *newpath;
1250 struct attr_extra *attre = attr->extra;
1251
1252 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1253 {
1254 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1255 * if given.
1256 * It is worth a warning though, because the peer really
1257 * should not send them
1258 */
1259 if (BGP_DEBUG(as4, AS4))
1260 {
1261 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1262 zlog_debug ("[AS4] %s %s AS4_PATH",
1263 peer->host, "AS4 capable peer, yet it sent");
1264
1265 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1266 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1267 peer->host, "AS4 capable peer, yet it sent");
1268 }
1269
1270 return 0;
1271 }
1272
1273 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1274 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1275 {
1276 /* Hu? This is not supposed to happen at all!
1277 * got as4_path and no aspath,
1278 * This should already
1279 * have been handled by 'well known attributes missing'
1280 * But... yeah, paranoia
1281 * Take this as a "malformed attribute"
1282 */
1283 zlog (peer->log, LOG_ERR,
1284 "%s BGP not AS4 capable peer sent AS4_PATH but"
1285 " no AS_PATH, cant do anything here", peer->host);
1286 bgp_notify_send (peer,
1287 BGP_NOTIFY_UPDATE_ERR,
1288 BGP_NOTIFY_UPDATE_MAL_ATTR);
1289 return -1;
1290 }
1291
1292 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1293 * because that may override AS4_PATH
1294 */
1295 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1296 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001297 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1298 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001299 assert (attre);
1300
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001301 /* received both.
1302 * if the as_number in aggregator is not AS_TRANS,
1303 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1304 * and the Aggregator shall be taken as
1305 * info on the aggregating node, and the AS_PATH
1306 * shall be taken as the AS_PATH
1307 * otherwise
1308 * the Aggregator shall be ignored and the
1309 * AS4_AGGREGATOR shall be taken as the
1310 * Aggregating node and the AS_PATH is to be
1311 * constructed "as in all other cases"
1312 */
1313 if ( attre->aggregator_as != BGP_AS_TRANS )
1314 {
1315 /* ignore */
1316 if ( BGP_DEBUG(as4, AS4))
1317 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1318 " send AGGREGATOR != AS_TRANS and"
1319 " AS4_AGGREGATOR, so ignore"
1320 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1321 ignore_as4_path = 1;
1322 }
1323 else
1324 {
1325 /* "New_aggregator shall be taken as aggregator" */
1326 attre->aggregator_as = as4_aggregator;
1327 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1328 }
1329 }
1330 else
1331 {
1332 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1333 * That is bogus - but reading the conditions
1334 * we have to handle AS4_AGGREGATOR as if it were
1335 * AGGREGATOR in that case
1336 */
1337 if ( BGP_DEBUG(as4, AS4))
1338 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1339 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1340 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001341 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001342 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1343 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1344 }
1345 }
1346
1347 /* need to reconcile NEW_AS_PATH and AS_PATH */
1348 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1349 {
1350 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1351 aspath_unintern (attr->aspath);
1352 attr->aspath = aspath_intern (newpath);
1353 }
1354 return 0;
1355}
1356
paul718e3742002-12-13 20:15:29 +00001357/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001358static int
paul718e3742002-12-13 20:15:29 +00001359bgp_attr_community (struct peer *peer, bgp_size_t length,
1360 struct attr *attr, u_char flag)
1361{
1362 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001363 {
1364 attr->community = NULL;
1365 return 0;
1366 }
Paul Jakmafc097162010-12-05 17:17:26 +00001367
1368 attr->community =
1369 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1370
1371 /* XXX: fix community_parse to use stream API and remove this */
1372 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001373
Paul Jakmafc097162010-12-05 17:17:26 +00001374 if (!attr->community)
1375 return -1;
1376
paul718e3742002-12-13 20:15:29 +00001377 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1378
1379 return 0;
1380}
1381
1382/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001383static int
paul718e3742002-12-13 20:15:29 +00001384bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1385 struct attr *attr, u_char flag)
1386{
1387 if (length != 4)
1388 {
1389 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1390
1391 bgp_notify_send (peer,
1392 BGP_NOTIFY_UPDATE_ERR,
1393 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1394 return -1;
1395 }
1396
Paul Jakmafb982c22007-05-04 20:15:47 +00001397 (bgp_attr_extra_get (attr))->originator_id.s_addr
1398 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001399
1400 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1401
1402 return 0;
1403}
1404
1405/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001406static int
paul718e3742002-12-13 20:15:29 +00001407bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1408 struct attr *attr, u_char flag)
1409{
1410 /* Check length. */
1411 if (length % 4)
1412 {
1413 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1414
1415 bgp_notify_send (peer,
1416 BGP_NOTIFY_UPDATE_ERR,
1417 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1418 return -1;
1419 }
1420
Paul Jakmafb982c22007-05-04 20:15:47 +00001421 (bgp_attr_extra_get (attr))->cluster
1422 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001423
paul9985f832005-02-09 15:51:56 +00001424 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001425
1426 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1427
1428 return 0;
1429}
1430
1431/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001432int
paul718e3742002-12-13 20:15:29 +00001433bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1434 struct bgp_nlri *mp_update)
1435{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001436 afi_t afi;
1437 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001438 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001439 size_t start;
paul718e3742002-12-13 20:15:29 +00001440 int ret;
1441 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001442 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001443
1444 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001445 s = BGP_INPUT(peer);
1446 start = stream_get_getp(s);
1447
1448 /* safe to read statically sized header? */
1449#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001450#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001451 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001452 {
1453 zlog_info ("%s: %s sent invalid length, %lu",
1454 __func__, peer->host, (unsigned long)length);
1455 return -1;
1456 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001457
paul718e3742002-12-13 20:15:29 +00001458 /* Load AFI, SAFI. */
1459 afi = stream_getw (s);
1460 safi = stream_getc (s);
1461
1462 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001463 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001464
Paul Jakma03292802008-06-07 20:37:10 +00001465 if (LEN_LEFT < attre->mp_nexthop_len)
1466 {
1467 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1468 __func__, peer->host, attre->mp_nexthop_len);
1469 return -1;
1470 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001471
paul718e3742002-12-13 20:15:29 +00001472 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001473 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001474 {
1475 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001476 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001477 /* Probably needed for RFC 2283 */
1478 if (attr->nexthop.s_addr == 0)
1479 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001480 break;
1481 case 12:
1482 {
1483 u_int32_t rd_high;
1484 u_int32_t rd_low;
1485
1486 rd_high = stream_getl (s);
1487 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001488 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001489 }
1490 break;
1491#ifdef HAVE_IPV6
1492 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001493 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001494 break;
1495 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001496 stream_get (&attre->mp_nexthop_global, s, 16);
1497 stream_get (&attre->mp_nexthop_local, s, 16);
1498 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001499 {
1500 char buf1[INET6_ADDRSTRLEN];
1501 char buf2[INET6_ADDRSTRLEN];
1502
1503 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001504 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 +00001505 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001506 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001507 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001508 buf2, INET6_ADDRSTRLEN));
1509
Paul Jakmafb982c22007-05-04 20:15:47 +00001510 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001511 }
1512 break;
1513#endif /* HAVE_IPV6 */
1514 default:
Paul Jakma03292802008-06-07 20:37:10 +00001515 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1516 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001517 return -1;
paul718e3742002-12-13 20:15:29 +00001518 }
1519
Paul Jakma03292802008-06-07 20:37:10 +00001520 if (!LEN_LEFT)
1521 {
1522 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1523 __func__, peer->host);
1524 return -1;
1525 }
paul718e3742002-12-13 20:15:29 +00001526
Paul Jakma6e4ab122007-04-10 19:36:48 +00001527 {
1528 u_char val;
1529 if ((val = stream_getc (s)))
1530 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1531 peer->host, val);
1532 }
1533
1534 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001535 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001536 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001537 {
1538 zlog_info ("%s: (%s) Failed to read NLRI",
1539 __func__, peer->host);
1540 return -1;
1541 }
paul718e3742002-12-13 20:15:29 +00001542
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001543 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001544 {
1545 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001546 if (ret < 0)
1547 {
1548 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1549 __func__, peer->host);
1550 return -1;
1551 }
paul718e3742002-12-13 20:15:29 +00001552 }
1553
1554 mp_update->afi = afi;
1555 mp_update->safi = safi;
1556 mp_update->nlri = stream_pnt (s);
1557 mp_update->length = nlri_len;
1558
paul9985f832005-02-09 15:51:56 +00001559 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001560
1561 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001562#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001563}
1564
1565/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001566int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001567bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001568 struct bgp_nlri *mp_withdraw)
1569{
1570 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001571 afi_t afi;
1572 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001573 u_int16_t withdraw_len;
1574 int ret;
1575
1576 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001577
1578#define BGP_MP_UNREACH_MIN_SIZE 3
1579 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1580 return -1;
1581
paul718e3742002-12-13 20:15:29 +00001582 afi = stream_getw (s);
1583 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001584
1585 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001586
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001587 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001588 {
1589 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1590 if (ret < 0)
1591 return -1;
1592 }
1593
1594 mp_withdraw->afi = afi;
1595 mp_withdraw->safi = safi;
1596 mp_withdraw->nlri = stream_pnt (s);
1597 mp_withdraw->length = withdraw_len;
1598
paul9985f832005-02-09 15:51:56 +00001599 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001600
1601 return 0;
1602}
1603
1604/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001605static int
paul718e3742002-12-13 20:15:29 +00001606bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1607 struct attr *attr, u_char flag)
1608{
1609 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001610 {
1611 if (attr->extra)
1612 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001613 /* Empty extcomm doesn't seem to be invalid per se */
1614 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001615 }
Paul Jakmafc097162010-12-05 17:17:26 +00001616
1617 (bgp_attr_extra_get (attr))->ecommunity =
1618 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1619 /* XXX: fix ecommunity_parse to use stream API */
1620 stream_forward_getp (peer->ibuf, length);
1621
1622 if (!attr->extra->ecommunity)
1623 return -1;
1624
paul718e3742002-12-13 20:15:29 +00001625 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1626
1627 return 0;
1628}
1629
1630/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001631static int
paul718e3742002-12-13 20:15:29 +00001632bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1633 u_char type, bgp_size_t length, u_char *startp)
1634{
1635 bgp_size_t total;
1636 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001637 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001638
hassof4184462005-02-01 20:13:16 +00001639 if (BGP_DEBUG (normal, NORMAL))
1640 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1641 peer->host, type, length);
1642
paul718e3742002-12-13 20:15:29 +00001643 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001644 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001645 "Unknown attribute type %d length %d is received", type, length);
1646
1647 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001648 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001649
1650 /* Adjest total length to include type and length. */
1651 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1652
1653 /* If any of the mandatory well-known attributes are not recognized,
1654 then the Error Subcode is set to Unrecognized Well-known
1655 Attribute. The Data field contains the unrecognized attribute
1656 (type, length and value). */
1657 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1658 {
1659 /* Adjust startp to do not include flag value. */
1660 bgp_notify_send_with_data (peer,
1661 BGP_NOTIFY_UPDATE_ERR,
1662 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1663 startp, total);
1664 return -1;
1665 }
1666
1667 /* Unrecognized non-transitive optional attributes must be quietly
1668 ignored and not passed along to other BGP peers. */
1669 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1670 return 0;
1671
1672 /* If a path with recognized transitive optional attribute is
1673 accepted and passed along to other BGP peers and the Partial bit
1674 in the Attribute Flags octet is set to 1 by some previous AS, it
1675 is not set back to 0 by the current AS. */
1676 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1677
1678 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001679 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001680 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001681
Paul Jakmafb982c22007-05-04 20:15:47 +00001682 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001683
1684 if (transit->val)
1685 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1686 transit->length + total);
1687 else
1688 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1689
1690 memcpy (transit->val + transit->length, startp, total);
1691 transit->length += total;
1692
1693 return 0;
1694}
1695
1696/* Read attribute of update packet. This function is called from
1697 bgp_update() in bgpd.c. */
1698int
1699bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1700 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1701{
1702 int ret;
1703 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001704 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001705 bgp_size_t length;
1706 u_char *startp, *endp;
1707 u_char *attr_endp;
1708 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001709 /* we need the as4_path only until we have synthesized the as_path with it */
1710 /* same goes for as4_aggregator */
1711 struct aspath *as4_path = NULL;
1712 as_t as4_aggregator = 0;
1713 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001714
1715 /* Initialize bitmap. */
1716 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1717
1718 /* End pointer of BGP attribute. */
1719 endp = BGP_INPUT_PNT (peer) + size;
1720
1721 /* Get attributes to the end of attribute length. */
1722 while (BGP_INPUT_PNT (peer) < endp)
1723 {
1724 /* Check remaining length check.*/
1725 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1726 {
gdtc29fdba2004-12-09 14:46:46 +00001727 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001728 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001729 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001730 peer->host,
1731 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001732
1733 bgp_notify_send (peer,
1734 BGP_NOTIFY_UPDATE_ERR,
1735 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1736 return -1;
1737 }
1738
1739 /* Fetch attribute flag and type. */
1740 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001741 /* "The lower-order four bits of the Attribute Flags octet are
1742 unused. They MUST be zero when sent and MUST be ignored when
1743 received." */
1744 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001745 type = stream_getc (BGP_INPUT (peer));
1746
Paul Jakma370b64a2007-12-22 16:49:52 +00001747 /* Check whether Extended-Length applies and is in bounds */
1748 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1749 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1750 {
1751 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001752 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001753 peer->host,
1754 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1755
1756 bgp_notify_send (peer,
1757 BGP_NOTIFY_UPDATE_ERR,
1758 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1759 return -1;
1760 }
1761
paul718e3742002-12-13 20:15:29 +00001762 /* Check extended attribue length bit. */
1763 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1764 length = stream_getw (BGP_INPUT (peer));
1765 else
1766 length = stream_getc (BGP_INPUT (peer));
1767
1768 /* If any attribute appears more than once in the UPDATE
1769 message, then the Error Subcode is set to Malformed Attribute
1770 List. */
1771
1772 if (CHECK_BITMAP (seen, type))
1773 {
1774 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001775 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001776 peer->host, type);
1777
1778 bgp_notify_send (peer,
1779 BGP_NOTIFY_UPDATE_ERR,
1780 BGP_NOTIFY_UPDATE_MAL_ATTR);
1781 return -1;
1782 }
1783
1784 /* Set type to bitmap to check duplicate attribute. `type' is
1785 unsigned char so it never overflow bitmap range. */
1786
1787 SET_BITMAP (seen, type);
1788
1789 /* Overflow check. */
1790 attr_endp = BGP_INPUT_PNT (peer) + length;
1791
1792 if (attr_endp > endp)
1793 {
1794 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001795 "%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 +00001796 bgp_notify_send (peer,
1797 BGP_NOTIFY_UPDATE_ERR,
1798 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1799 return -1;
1800 }
1801
1802 /* OK check attribute and store it's value. */
1803 switch (type)
1804 {
1805 case BGP_ATTR_ORIGIN:
1806 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1807 break;
1808 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001809 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1810 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001811 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001812 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001813 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1814 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001815 break;
paul718e3742002-12-13 20:15:29 +00001816 case BGP_ATTR_NEXT_HOP:
1817 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1818 break;
1819 case BGP_ATTR_MULTI_EXIT_DISC:
1820 ret = bgp_attr_med (peer, length, attr, flag, startp);
1821 break;
1822 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001823 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001824 break;
1825 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001826 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001827 break;
1828 case BGP_ATTR_AGGREGATOR:
1829 ret = bgp_attr_aggregator (peer, length, attr, flag);
1830 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001831 case BGP_ATTR_AS4_AGGREGATOR:
1832 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1833 break;
paul718e3742002-12-13 20:15:29 +00001834 case BGP_ATTR_COMMUNITIES:
1835 ret = bgp_attr_community (peer, length, attr, flag);
1836 break;
1837 case BGP_ATTR_ORIGINATOR_ID:
1838 ret = bgp_attr_originator_id (peer, length, attr, flag);
1839 break;
1840 case BGP_ATTR_CLUSTER_LIST:
1841 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1842 break;
1843 case BGP_ATTR_MP_REACH_NLRI:
1844 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1845 break;
1846 case BGP_ATTR_MP_UNREACH_NLRI:
1847 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1848 break;
1849 case BGP_ATTR_EXT_COMMUNITIES:
1850 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1851 break;
1852 default:
1853 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1854 break;
1855 }
1856
1857 /* If error occured immediately return to the caller. */
1858 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001859 {
1860 zlog (peer->log, LOG_WARNING,
1861 "%s: Attribute %s, parse error",
1862 peer->host,
1863 LOOKUP (attr_str, type));
1864 bgp_notify_send (peer,
1865 BGP_NOTIFY_UPDATE_ERR,
1866 BGP_NOTIFY_UPDATE_MAL_ATTR);
1867 return ret;
1868 }
paul718e3742002-12-13 20:15:29 +00001869
1870 /* Check the fetched length. */
1871 if (BGP_INPUT_PNT (peer) != attr_endp)
1872 {
1873 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001874 "%s: BGP attribute %s, fetch error",
1875 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001876 bgp_notify_send (peer,
1877 BGP_NOTIFY_UPDATE_ERR,
1878 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1879 return -1;
1880 }
1881 }
1882
1883 /* Check final read pointer is same as end pointer. */
1884 if (BGP_INPUT_PNT (peer) != endp)
1885 {
1886 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001887 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001888 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001889 bgp_notify_send (peer,
1890 BGP_NOTIFY_UPDATE_ERR,
1891 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1892 return -1;
1893 }
1894
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001895 /*
1896 * At this place we can see whether we got AS4_PATH and/or
1897 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1898 * We can not do this before we've read all attributes because
1899 * the as4 handling does not say whether AS4_PATH has to be sent
1900 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1901 * in relationship to AGGREGATOR.
1902 * So, to be defensive, we are not relying on any order and read
1903 * all attributes first, including these 32bit ones, and now,
1904 * afterwards, we look what and if something is to be done for as4.
1905 */
1906 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1907 as4_aggregator, &as4_aggregator_addr))
1908 return -1;
1909
1910 /* At this stage, we have done all fiddling with as4, and the
1911 * resulting info is in attr->aggregator resp. attr->aspath
1912 * so we can chuck as4_aggregator and as4_path alltogether in
1913 * order to save memory
1914 */
1915 if ( as4_path )
1916 {
1917 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1918 as4_path = NULL;
1919 /* The flag that we got this is still there, but that does not
1920 * do any trouble
1921 */
1922 }
1923 /*
1924 * The "rest" of the code does nothing with as4_aggregator.
1925 * there is no memory attached specifically which is not part
1926 * of the attr.
1927 * so ignoring just means do nothing.
1928 */
1929 /*
1930 * Finally do the checks on the aspath we did not do yet
1931 * because we waited for a potentially synthesized aspath.
1932 */
1933 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1934 {
1935 ret = bgp_attr_aspath_check( peer, attr );
1936 if ( ret < 0 )
1937 return ret;
1938 }
1939
paul718e3742002-12-13 20:15:29 +00001940 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001941 if (attr->extra && attr->extra->transit)
1942 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001943
1944 return 0;
1945}
1946
1947/* Well-known attribute check. */
1948int
1949bgp_attr_check (struct peer *peer, struct attr *attr)
1950{
1951 u_char type = 0;
1952
1953 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1954 type = BGP_ATTR_ORIGIN;
1955
1956 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1957 type = BGP_ATTR_AS_PATH;
1958
1959 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1960 type = BGP_ATTR_NEXT_HOP;
1961
1962 if (peer_sort (peer) == BGP_PEER_IBGP
1963 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1964 type = BGP_ATTR_LOCAL_PREF;
1965
1966 if (type)
1967 {
1968 zlog (peer->log, LOG_WARNING,
1969 "%s Missing well-known attribute %d.",
1970 peer->host, type);
1971 bgp_notify_send_with_data (peer,
1972 BGP_NOTIFY_UPDATE_ERR,
1973 BGP_NOTIFY_UPDATE_MISS_ATTR,
1974 &type, 1);
1975 return -1;
1976 }
1977 return 0;
1978}
1979
1980int stream_put_prefix (struct stream *, struct prefix *);
1981
1982/* Make attribute packet. */
1983bgp_size_t
1984bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1985 struct stream *s, struct attr *attr, struct prefix *p,
1986 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001987 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001988{
paulfe69a502005-09-10 16:55:02 +00001989 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001990 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001991 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001992 int send_as4_path = 0;
1993 int send_as4_aggregator = 0;
1994 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001995
1996 if (! bgp)
1997 bgp = bgp_get_default ();
1998
1999 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002000 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002001
2002 /* Origin attribute. */
2003 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2004 stream_putc (s, BGP_ATTR_ORIGIN);
2005 stream_putc (s, 1);
2006 stream_putc (s, attr->origin);
2007
2008 /* AS path attribute. */
2009
2010 /* If remote-peer is EBGP */
2011 if (peer_sort (peer) == BGP_PEER_EBGP
2012 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002013 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002014 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002015 {
2016 aspath = aspath_dup (attr->aspath);
2017
2018 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2019 {
2020 /* Strip the confed info, and then stuff our path CONFED_ID
2021 on the front */
2022 aspath = aspath_delete_confed_seq (aspath);
2023 aspath = aspath_add_seq (aspath, bgp->confed_id);
2024 }
2025 else
2026 {
2027 aspath = aspath_add_seq (aspath, peer->local_as);
2028 if (peer->change_local_as)
2029 aspath = aspath_add_seq (aspath, peer->change_local_as);
2030 }
2031 }
2032 else if (peer_sort (peer) == BGP_PEER_CONFED)
2033 {
2034 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2035 aspath = aspath_dup (attr->aspath);
2036 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2037 }
2038 else
2039 aspath = attr->aspath;
2040
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002041 /* If peer is not AS4 capable, then:
2042 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2043 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2044 * types are in it (i.e. exclude them if they are there)
2045 * AND do this only if there is at least one asnum > 65535 in the path!
2046 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2047 * all ASnums > 65535 to BGP_AS_TRANS
2048 */
paul718e3742002-12-13 20:15:29 +00002049
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002050 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2051 stream_putc (s, BGP_ATTR_AS_PATH);
2052 aspath_sizep = stream_get_endp (s);
2053 stream_putw (s, 0);
2054 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2055
2056 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2057 * in the path
2058 */
2059 if (!use32bit && aspath_has_as4 (aspath))
2060 send_as4_path = 1; /* we'll do this later, at the correct place */
2061
paul718e3742002-12-13 20:15:29 +00002062 /* Nexthop attribute. */
2063 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2064 {
2065 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2066 stream_putc (s, BGP_ATTR_NEXT_HOP);
2067 stream_putc (s, 4);
2068 if (safi == SAFI_MPLS_VPN)
2069 {
2070 if (attr->nexthop.s_addr == 0)
2071 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2072 else
2073 stream_put_ipv4 (s, attr->nexthop.s_addr);
2074 }
2075 else
2076 stream_put_ipv4 (s, attr->nexthop.s_addr);
2077 }
2078
2079 /* MED attribute. */
2080 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2081 {
2082 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2083 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2084 stream_putc (s, 4);
2085 stream_putl (s, attr->med);
2086 }
2087
2088 /* Local preference. */
2089 if (peer_sort (peer) == BGP_PEER_IBGP ||
2090 peer_sort (peer) == BGP_PEER_CONFED)
2091 {
2092 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2093 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2094 stream_putc (s, 4);
2095 stream_putl (s, attr->local_pref);
2096 }
2097
2098 /* Atomic aggregate. */
2099 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2100 {
2101 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2102 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2103 stream_putc (s, 0);
2104 }
2105
2106 /* Aggregator. */
2107 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2108 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002109 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002110
2111 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002112 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2113 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002114
2115 if (use32bit)
2116 {
2117 /* AS4 capable peer */
2118 stream_putc (s, 8);
2119 stream_putl (s, attr->extra->aggregator_as);
2120 }
2121 else
2122 {
2123 /* 2-byte AS peer */
2124 stream_putc (s, 6);
2125
2126 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2127 if ( attr->extra->aggregator_as > 65535 )
2128 {
2129 stream_putw (s, BGP_AS_TRANS);
2130
2131 /* we have to send AS4_AGGREGATOR, too.
2132 * we'll do that later in order to send attributes in ascending
2133 * order.
2134 */
2135 send_as4_aggregator = 1;
2136 }
2137 else
2138 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2139 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002140 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002141 }
2142
2143 /* Community attribute. */
2144 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2145 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2146 {
2147 if (attr->community->size * 4 > 255)
2148 {
2149 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2150 stream_putc (s, BGP_ATTR_COMMUNITIES);
2151 stream_putw (s, attr->community->size * 4);
2152 }
2153 else
2154 {
2155 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2156 stream_putc (s, BGP_ATTR_COMMUNITIES);
2157 stream_putc (s, attr->community->size * 4);
2158 }
2159 stream_put (s, attr->community->val, attr->community->size * 4);
2160 }
2161
2162 /* Route Reflector. */
2163 if (peer_sort (peer) == BGP_PEER_IBGP
2164 && from
2165 && peer_sort (from) == BGP_PEER_IBGP)
2166 {
2167 /* Originator ID. */
2168 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2169 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2170 stream_putc (s, 4);
2171
2172 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002173 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002174 else
2175 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002176
2177 /* Cluster list. */
2178 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2179 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2180
Paul Jakma9eda90c2007-08-30 13:36:17 +00002181 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002182 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002183 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002184 /* If this peer configuration's parent BGP has cluster_id. */
2185 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2186 stream_put_in_addr (s, &bgp->cluster_id);
2187 else
2188 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002189 stream_put (s, attr->extra->cluster->list,
2190 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002191 }
2192 else
2193 {
2194 stream_putc (s, 4);
2195 /* If this peer configuration's parent BGP has cluster_id. */
2196 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2197 stream_put_in_addr (s, &bgp->cluster_id);
2198 else
2199 stream_put_in_addr (s, &bgp->router_id);
2200 }
2201 }
2202
2203#ifdef HAVE_IPV6
2204 /* If p is IPv6 address put it into attribute. */
2205 if (p->family == AF_INET6)
2206 {
2207 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002208 struct attr_extra *attre = attr->extra;
2209
2210 assert (attr->extra);
2211
paul718e3742002-12-13 20:15:29 +00002212 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2213 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002214 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002215 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002216 stream_putw (s, AFI_IP6); /* AFI */
2217 stream_putc (s, safi); /* SAFI */
2218
Paul Jakmafb982c22007-05-04 20:15:47 +00002219 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002220
Paul Jakmafb982c22007-05-04 20:15:47 +00002221 if (attre->mp_nexthop_len == 16)
2222 stream_put (s, &attre->mp_nexthop_global, 16);
2223 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002224 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002225 stream_put (s, &attre->mp_nexthop_global, 16);
2226 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002227 }
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#endif /* HAVE_IPV6 */
2239
2240 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2241 {
2242 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002243
2244 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2245 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002246 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002247 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002248 stream_putw (s, AFI_IP); /* AFI */
2249 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2250
2251 stream_putc (s, 4);
2252 stream_put_ipv4 (s, attr->nexthop.s_addr);
2253
2254 /* SNPA */
2255 stream_putc (s, 0);
2256
paul718e3742002-12-13 20:15:29 +00002257 /* Prefix write. */
2258 stream_put_prefix (s, p);
2259
2260 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002261 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002262 }
2263
2264 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2265 {
2266 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002267
2268 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2269 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002270 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002271 stream_putc (s, 0); /* Length of this attribute. */
2272 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002273 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002274
2275 stream_putc (s, 12);
2276 stream_putl (s, 0);
2277 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002278 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002279
2280 /* SNPA */
2281 stream_putc (s, 0);
2282
paul718e3742002-12-13 20:15:29 +00002283 /* Tag, RD, Prefix write. */
2284 stream_putc (s, p->prefixlen + 88);
2285 stream_put (s, tag, 3);
2286 stream_put (s, prd->val, 8);
2287 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2288
2289 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002290 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002291 }
2292
2293 /* Extended Communities attribute. */
2294 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2295 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2296 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002297 struct attr_extra *attre = attr->extra;
2298
2299 assert (attre);
2300
2301 if (peer_sort (peer) == BGP_PEER_IBGP
2302 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002303 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002304 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002305 {
2306 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2307 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002308 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002309 }
2310 else
2311 {
2312 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2313 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002314 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002315 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002316 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002317 }
2318 else
2319 {
paul5228ad22004-06-04 17:58:18 +00002320 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002321 int tbit;
2322 int ecom_tr_size = 0;
2323 int i;
2324
Paul Jakmafb982c22007-05-04 20:15:47 +00002325 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002326 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002327 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002328 tbit = *pnt;
2329
2330 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2331 continue;
2332
2333 ecom_tr_size++;
2334 }
2335
2336 if (ecom_tr_size)
2337 {
2338 if (ecom_tr_size * 8 > 255)
2339 {
2340 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2341 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2342 stream_putw (s, ecom_tr_size * 8);
2343 }
2344 else
2345 {
2346 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2347 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2348 stream_putc (s, ecom_tr_size * 8);
2349 }
2350
Paul Jakmafb982c22007-05-04 20:15:47 +00002351 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002352 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002353 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002354 tbit = *pnt;
2355
2356 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2357 continue;
2358
2359 stream_put (s, pnt, 8);
2360 }
2361 }
paul718e3742002-12-13 20:15:29 +00002362 }
paul718e3742002-12-13 20:15:29 +00002363 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002364
2365 if ( send_as4_path )
2366 {
2367 /* If the peer is NOT As4 capable, AND */
2368 /* there are ASnums > 65535 in path THEN
2369 * give out AS4_PATH */
2370
2371 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2372 * path segments!
2373 * Hm, I wonder... confederation things *should* only be at
2374 * the beginning of an aspath, right? Then we should use
2375 * aspath_delete_confed_seq for this, because it is already
2376 * there! (JK)
2377 * Folks, talk to me: what is reasonable here!?
2378 */
2379 aspath = aspath_delete_confed_seq (aspath);
2380
2381 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2382 stream_putc (s, BGP_ATTR_AS4_PATH);
2383 aspath_sizep = stream_get_endp (s);
2384 stream_putw (s, 0);
2385 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2386 }
2387
2388 if (aspath != attr->aspath)
2389 aspath_free (aspath);
2390
2391 if ( send_as4_aggregator )
2392 {
2393 assert (attr->extra);
2394
2395 /* send AS4_AGGREGATOR, at this place */
2396 /* this section of code moved here in order to ensure the correct
2397 * *ascending* order of attributes
2398 */
2399 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2400 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2401 stream_putc (s, 8);
2402 stream_putl (s, attr->extra->aggregator_as);
2403 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2404 }
Paul Jakma41367172007-08-06 15:24:51 +00002405
paul718e3742002-12-13 20:15:29 +00002406 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002407 if (attr->extra && attr->extra->transit)
2408 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002409
2410 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002411 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002412}
2413
2414bgp_size_t
2415bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2416 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002417 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002418{
2419 unsigned long cp;
2420 unsigned long attrlen_pnt;
2421 bgp_size_t size;
2422
paul9985f832005-02-09 15:51:56 +00002423 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002424
2425 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2426 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2427
paul9985f832005-02-09 15:51:56 +00002428 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002429 stream_putc (s, 0); /* Length of this attribute. */
2430
2431 stream_putw (s, family2afi (p->family));
2432
2433 if (safi == SAFI_MPLS_VPN)
2434 {
2435 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002436 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002437
2438 /* prefix. */
2439 stream_putc (s, p->prefixlen + 88);
2440 stream_put (s, tag, 3);
2441 stream_put (s, prd->val, 8);
2442 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2443 }
2444 else
2445 {
2446 /* SAFI */
2447 stream_putc (s, safi);
2448
2449 /* prefix */
2450 stream_put_prefix (s, p);
2451 }
2452
2453 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002454 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002455 stream_putc_at (s, attrlen_pnt, size);
2456
paul9985f832005-02-09 15:51:56 +00002457 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002458}
2459
2460/* Initialization of attribute. */
2461void
paulfe69a502005-09-10 16:55:02 +00002462bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002463{
paul718e3742002-12-13 20:15:29 +00002464 aspath_init ();
2465 attrhash_init ();
2466 community_init ();
2467 ecommunity_init ();
2468 cluster_init ();
2469 transit_init ();
2470}
2471
Chris Caputo228da422009-07-18 05:44:03 +00002472void
2473bgp_attr_finish (void)
2474{
2475 aspath_finish ();
2476 attrhash_finish ();
2477 community_finish ();
2478 ecommunity_finish ();
2479 cluster_finish ();
2480 transit_finish ();
2481}
2482
paul718e3742002-12-13 20:15:29 +00002483/* Make attribute packet. */
2484void
paula3845922003-10-18 01:30:50 +00002485bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2486 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002487{
2488 unsigned long cp;
2489 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002490 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002491 struct aspath *aspath;
2492
2493 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002494 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002495
2496 /* Place holder of length. */
2497 stream_putw (s, 0);
2498
2499 /* Origin attribute. */
2500 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2501 stream_putc (s, BGP_ATTR_ORIGIN);
2502 stream_putc (s, 1);
2503 stream_putc (s, attr->origin);
2504
2505 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002506
2507 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2508 stream_putc (s, BGP_ATTR_AS_PATH);
2509 aspath_lenp = stream_get_endp (s);
2510 stream_putw (s, 0);
2511
2512 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002513
2514 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002515 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2516 if(prefix != NULL
2517#ifdef HAVE_IPV6
2518 && prefix->family != AF_INET6
2519#endif /* HAVE_IPV6 */
2520 )
2521 {
2522 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2523 stream_putc (s, BGP_ATTR_NEXT_HOP);
2524 stream_putc (s, 4);
2525 stream_put_ipv4 (s, attr->nexthop.s_addr);
2526 }
paul718e3742002-12-13 20:15:29 +00002527
2528 /* MED attribute. */
2529 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2530 {
2531 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2532 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2533 stream_putc (s, 4);
2534 stream_putl (s, attr->med);
2535 }
2536
2537 /* Local preference. */
2538 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2539 {
2540 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2541 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2542 stream_putc (s, 4);
2543 stream_putl (s, attr->local_pref);
2544 }
2545
2546 /* Atomic aggregate. */
2547 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2548 {
2549 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2550 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2551 stream_putc (s, 0);
2552 }
2553
2554 /* Aggregator. */
2555 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2556 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002557 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002558 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2559 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002560 stream_putc (s, 8);
2561 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002562 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002563 }
2564
2565 /* Community attribute. */
2566 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2567 {
2568 if (attr->community->size * 4 > 255)
2569 {
2570 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2571 stream_putc (s, BGP_ATTR_COMMUNITIES);
2572 stream_putw (s, attr->community->size * 4);
2573 }
2574 else
2575 {
2576 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2577 stream_putc (s, BGP_ATTR_COMMUNITIES);
2578 stream_putc (s, attr->community->size * 4);
2579 }
2580 stream_put (s, attr->community->val, attr->community->size * 4);
2581 }
2582
paula3845922003-10-18 01:30:50 +00002583#ifdef HAVE_IPV6
2584 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002585 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2586 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002587 {
2588 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002589 struct attr_extra *attre = attr->extra;
2590
paula3845922003-10-18 01:30:50 +00002591 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2592 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002593 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002594
2595 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002596 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002597 stream_putw(s, AFI_IP6); /* AFI */
2598 stream_putc(s, SAFI_UNICAST); /* SAFI */
2599
2600 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002601 stream_putc(s, attre->mp_nexthop_len);
2602 stream_put(s, &attre->mp_nexthop_global, 16);
2603 if (attre->mp_nexthop_len == 32)
2604 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002605
2606 /* SNPA */
2607 stream_putc(s, 0);
2608
2609 /* Prefix */
2610 stream_put_prefix(s, prefix);
2611
2612 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002613 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002614 }
2615#endif /* HAVE_IPV6 */
2616
paul718e3742002-12-13 20:15:29 +00002617 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002618 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002619 stream_putw_at (s, cp, len);
2620}