blob: 8966c5ed048be6e137350d7516a1213bf30ace6c [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070042static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
Denis Ovsienko452db842011-10-10 16:52:20 +040053 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
paul718e3742002-12-13 20:15:29 +000054 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000059 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
60 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
61 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
62 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000063};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070064static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
Stephen Hemminger9bddac42009-05-15 09:59:51 -070066static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000067
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 struct cluster_list *cluster;
73
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
76
77 if (cluster->length)
78 {
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
81 }
82 else
83 cluster->list = NULL;
84
85 cluster->refcnt = 0;
86
87 return cluster;
88}
89
90/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
103}
104
105int
106cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
107{
108 int i;
109
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
114}
115
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
123
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
126
127 while (length)
128 key += pnt[--length];
129
130 return key;
131}
132
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
Chris Caputo228da422009-07-18 05:44:03 +0000151#if 0
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
Stephen Hemminger393deb92008-08-18 14:13:29 -0700157 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
Chris Caputo228da422009-07-18 05:44:03 +0000170#endif
paul718e3742002-12-13 20:15:29 +0000171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
246 struct transit *ret;
247
248 if (transit->refcnt)
249 transit->refcnt--;
250
251 if (transit->refcnt == 0)
252 {
253 ret = hash_release (transit_hash, transit);
254 transit_free (transit);
255 }
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000259transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma923de652007-04-29 18:25:17 +0000261 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000262 unsigned int key = 0;
263 int length;
264 caddr_t pnt;
265
266 length = transit->length;
267 pnt = (caddr_t) transit->val;
268
269 while (length)
270 key += pnt[--length];
271
272 return key;
273}
274
paul94f2b392005-06-28 12:44:16 +0000275static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100276transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000277{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100278 const struct transit * transit1 = p1;
279 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000280
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100281 return (transit1->length == transit2->length &&
282 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000283}
284
paul94f2b392005-06-28 12:44:16 +0000285static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800286transit_init (void)
paul718e3742002-12-13 20:15:29 +0000287{
288 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
289}
Chris Caputo228da422009-07-18 05:44:03 +0000290
291static void
292transit_finish (void)
293{
294 hash_free (transit_hash);
295 transit_hash = NULL;
296}
paul718e3742002-12-13 20:15:29 +0000297
298/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700299static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000300
Paul Jakmafb982c22007-05-04 20:15:47 +0000301static struct attr_extra *
302bgp_attr_extra_new (void)
303{
304 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
305}
306
307void
308bgp_attr_extra_free (struct attr *attr)
309{
310 if (attr->extra)
311 {
312 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
313 attr->extra = NULL;
314 }
315}
316
317struct attr_extra *
318bgp_attr_extra_get (struct attr *attr)
319{
320 if (!attr->extra)
321 attr->extra = bgp_attr_extra_new();
322 return attr->extra;
323}
324
325/* Shallow copy of an attribute
326 * Though, not so shallow that it doesn't copy the contents
327 * of the attr_extra pointed to by 'extra'
328 */
329void
330bgp_attr_dup (struct attr *new, struct attr *orig)
331{
332 *new = *orig;
333 if (orig->extra)
334 {
335 new->extra = bgp_attr_extra_new();
336 *new->extra = *orig->extra;
337 }
338}
339
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000340unsigned long int
341attr_count (void)
342{
343 return attrhash->count;
344}
345
346unsigned long int
347attr_unknown_count (void)
348{
349 return transit_hash->count;
350}
351
paul718e3742002-12-13 20:15:29 +0000352unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000353attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000354{
Paul Jakma923de652007-04-29 18:25:17 +0000355 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000356 unsigned int key = 0;
357
358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000362
363 if (attr->extra)
364 {
365 key += attr->extra->aggregator_as;
366 key += attr->extra->aggregator_addr.s_addr;
367 key += attr->extra->weight;
368 key += attr->extra->mp_nexthop_global_in.s_addr;
369 }
370
paul718e3742002-12-13 20:15:29 +0000371 if (attr->aspath)
372 key += aspath_key_make (attr->aspath);
373 if (attr->community)
374 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000375
376 if (attr->extra)
377 {
378 if (attr->extra->ecommunity)
379 key += ecommunity_hash_make (attr->extra->ecommunity);
380 if (attr->extra->cluster)
381 key += cluster_hash_key_make (attr->extra->cluster);
382 if (attr->extra->transit)
383 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000384
385#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 {
387 int i;
388
389 key += attr->extra->mp_nexthop_len;
390 for (i = 0; i < 16; i++)
391 key += attr->extra->mp_nexthop_global.s6_addr[i];
392 for (i = 0; i < 16; i++)
393 key += attr->extra->mp_nexthop_local.s6_addr[i];
394 }
paul718e3742002-12-13 20:15:29 +0000395#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000396 }
paul718e3742002-12-13 20:15:29 +0000397
398 return key;
399}
400
401int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100402attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000403{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100404 const struct attr * attr1 = p1;
405 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000406
paul718e3742002-12-13 20:15:29 +0000407 if (attr1->flag == attr2->flag
408 && attr1->origin == attr2->origin
409 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000410 && attr1->aspath == attr2->aspath
411 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000412 && attr1->med == attr2->med
Paul Jakmae70e5752011-07-05 00:41:59 +0400413 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000414 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100415 const struct attr_extra *ae1 = attr1->extra;
416 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000417
418 if (ae1 && ae2
419 && ae1->aggregator_as == ae2->aggregator_as
420 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
421 && ae1->weight == ae2->weight
422#ifdef HAVE_IPV6
423 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
424 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
425 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
426#endif /* HAVE_IPV6 */
427 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
428 && ae1->ecommunity == ae2->ecommunity
429 && ae1->cluster == ae2->cluster
430 && ae1->transit == ae2->transit)
431 return 1;
432 else if (ae1 || ae2)
433 return 0;
434 /* neither attribute has extra attributes, so they're same */
435 return 1;
436 }
paul718e3742002-12-13 20:15:29 +0000437 else
438 return 0;
439}
440
paul94f2b392005-06-28 12:44:16 +0000441static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100442attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000443{
444 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
445}
446
paul94f2b392005-06-28 12:44:16 +0000447static void
Chris Caputo228da422009-07-18 05:44:03 +0000448attrhash_finish (void)
449{
450 hash_free (attrhash);
451 attrhash = NULL;
452}
453
454static void
paul718e3742002-12-13 20:15:29 +0000455attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
456{
457 struct attr *attr = backet->data;
458
459 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
460 inet_ntoa (attr->nexthop), VTY_NEWLINE);
461}
462
463void
464attr_show_all (struct vty *vty)
465{
466 hash_iterate (attrhash,
467 (void (*)(struct hash_backet *, void *))
468 attr_show_all_iterator,
469 vty);
470}
471
paul94f2b392005-06-28 12:44:16 +0000472static void *
Paul Jakma923de652007-04-29 18:25:17 +0000473bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000474{
Paul Jakma923de652007-04-29 18:25:17 +0000475 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000476 struct attr *attr;
477
478 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
479 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000480 if (val->extra)
481 {
482 attr->extra = bgp_attr_extra_new ();
483 *attr->extra = *val->extra;
484 }
paul718e3742002-12-13 20:15:29 +0000485 attr->refcnt = 0;
486 return attr;
487}
488
489/* Internet argument attribute. */
490struct attr *
491bgp_attr_intern (struct attr *attr)
492{
493 struct attr *find;
494
495 /* Intern referenced strucutre. */
496 if (attr->aspath)
497 {
498 if (! attr->aspath->refcnt)
499 attr->aspath = aspath_intern (attr->aspath);
500 else
501 attr->aspath->refcnt++;
502 }
503 if (attr->community)
504 {
505 if (! attr->community->refcnt)
506 attr->community = community_intern (attr->community);
507 else
508 attr->community->refcnt++;
509 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000510 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000511 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000512 struct attr_extra *attre = attr->extra;
513
514 if (attre->ecommunity)
515 {
516 if (! attre->ecommunity->refcnt)
517 attre->ecommunity = ecommunity_intern (attre->ecommunity);
518 else
519 attre->ecommunity->refcnt++;
520 }
521 if (attre->cluster)
522 {
523 if (! attre->cluster->refcnt)
524 attre->cluster = cluster_intern (attre->cluster);
525 else
526 attre->cluster->refcnt++;
527 }
528 if (attre->transit)
529 {
530 if (! attre->transit->refcnt)
531 attre->transit = transit_intern (attre->transit);
532 else
533 attre->transit->refcnt++;
534 }
paul718e3742002-12-13 20:15:29 +0000535 }
536
537 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
538 find->refcnt++;
539
540 return find;
541}
542
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544/* Make network statement's attribute. */
545struct attr *
546bgp_attr_default_set (struct attr *attr, u_char origin)
547{
548 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000549 bgp_attr_extra_get (attr);
550
paul718e3742002-12-13 20:15:29 +0000551 attr->origin = origin;
552 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
553 attr->aspath = aspath_empty ();
554 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000556 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
557#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000559#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000560
paul718e3742002-12-13 20:15:29 +0000561 return attr;
562}
563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564
paul718e3742002-12-13 20:15:29 +0000565/* Make network statement's attribute. */
566struct attr *
567bgp_attr_default_intern (u_char origin)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
572
573 memset (&attr, 0, sizeof (struct attr));
574 attre = bgp_attr_extra_get (&attr);
575
Paul Jakma03e214c2007-04-29 18:31:07 +0000576 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000577
578 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 bgp_attr_extra_free (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 aspath_unintern (new->aspath);
582 return new;
583}
584
585struct attr *
586bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
587 struct aspath *aspath,
588 struct community *community, int as_set)
589{
590 struct attr attr;
591 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000592 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000593
594 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000595 attre = bgp_attr_extra_get (&attr);
596
paul718e3742002-12-13 20:15:29 +0000597 /* Origin attribute. */
598 attr.origin = origin;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
600
601 /* AS path attribute. */
602 if (aspath)
603 attr.aspath = aspath_intern (aspath);
604 else
605 attr.aspath = aspath_empty ();
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
607
608 /* Next hop attribute. */
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
610
611 if (community)
612 {
613 attr.community = community;
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
615 }
616
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000618#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000619 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000620#endif
621 if (! as_set)
622 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
623 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
624 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000625 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000626 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 attre->aggregator_as = bgp->as;
628 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000629
630 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000631 bgp_attr_extra_free (&attr);
632
paul718e3742002-12-13 20:15:29 +0000633 aspath_unintern (new->aspath);
634 return new;
635}
636
637/* Free bgp attribute and aspath. */
638void
639bgp_attr_unintern (struct attr *attr)
640{
641 struct attr *ret;
642 struct aspath *aspath;
643 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000644 struct ecommunity *ecommunity = NULL;
645 struct cluster_list *cluster = NULL;
646 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000647
648 /* Decrement attribute reference. */
649 attr->refcnt--;
650 aspath = attr->aspath;
651 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000652 if (attr->extra)
653 {
654 ecommunity = attr->extra->ecommunity;
655 cluster = attr->extra->cluster;
656 transit = attr->extra->transit;
657 }
paul718e3742002-12-13 20:15:29 +0000658
659 /* If reference becomes zero then free attribute object. */
660 if (attr->refcnt == 0)
661 {
662 ret = hash_release (attrhash, attr);
663 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000664 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000665 XFREE (MTYPE_ATTR, attr);
666 }
667
668 /* aspath refcount shoud be decrement. */
669 if (aspath)
670 aspath_unintern (aspath);
671 if (community)
672 community_unintern (community);
673 if (ecommunity)
674 ecommunity_unintern (ecommunity);
675 if (cluster)
676 cluster_unintern (cluster);
677 if (transit)
678 transit_unintern (transit);
679}
680
681void
682bgp_attr_flush (struct attr *attr)
683{
684 if (attr->aspath && ! attr->aspath->refcnt)
685 aspath_free (attr->aspath);
686 if (attr->community && ! attr->community->refcnt)
687 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000688 if (attr->extra)
689 {
690 struct attr_extra *attre = attr->extra;
691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
692 ecommunity_free (attre->ecommunity);
693 if (attre->cluster && ! attre->cluster->refcnt)
694 cluster_free (attre->cluster);
695 if (attre->transit && ! attre->transit->refcnt)
696 transit_free (attre->transit);
697 }
paul718e3742002-12-13 20:15:29 +0000698}
699
700/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000701static int
paul718e3742002-12-13 20:15:29 +0000702bgp_attr_origin (struct peer *peer, bgp_size_t length,
703 struct attr *attr, u_char flag, u_char *startp)
704{
705 bgp_size_t total;
706
707 /* total is entire attribute length include Attribute Flags (1),
708 Attribute Type code (1) and Attribute length (1 or 2). */
709 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
710
711 /* If any recognized attribute has Attribute Flags that conflict
712 with the Attribute Type Code, then the Error Subcode is set to
713 Attribute Flags Error. The Data field contains the erroneous
714 attribute (type, length and value). */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400715 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400716 {
717 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
718 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
719 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
720 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
721 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
722 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
723 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
724 return -1;
725 }
paul718e3742002-12-13 20:15:29 +0000726
727 /* If any recognized attribute has Attribute Length that conflicts
728 with the expected length (based on the attribute type code), then
729 the Error Subcode is set to Attribute Length Error. The Data
730 field contains the erroneous attribute (type, length and
731 value). */
732 if (length != 1)
733 {
734 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
735 length);
736 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
737 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
738 startp, total);
739 return -1;
740 }
741
742 /* Fetch origin attribute. */
743 attr->origin = stream_getc (BGP_INPUT (peer));
744
745 /* If the ORIGIN attribute has an undefined value, then the Error
746 Subcode is set to Invalid Origin Attribute. The Data field
747 contains the unrecognized attribute (type, length and value). */
748 if ((attr->origin != BGP_ORIGIN_IGP)
749 && (attr->origin != BGP_ORIGIN_EGP)
750 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
751 {
752 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
753 attr->origin);
754
755 bgp_notify_send_with_data (peer,
756 BGP_NOTIFY_UPDATE_ERR,
757 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
758 startp, total);
759 return -1;
760 }
761
762 /* Set oring attribute flag. */
763 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
764
765 return 0;
766}
Chris Hallcddb8112010-08-09 22:31:37 +0400767/* Parse AS path information. This function is wrapper of aspath_parse.
768 *
769 * Parses AS_PATH or AS4_PATH.
770 *
771 * Returns: if valid: address of struct aspath in the hash of known aspaths,
772 * with reference count incremented.
773 * else: NULL
774 *
775 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
776 * have segments == NULL and str == zero length string (unique).
777 */
778static struct aspath *
paul718e3742002-12-13 20:15:29 +0000779bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400780 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000781{
Chris Hallcddb8112010-08-09 22:31:37 +0400782 u_char require ;
783 struct aspath *asp ;
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400784 bgp_size_t total;
785
786 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000787
Chris Hallcddb8112010-08-09 22:31:37 +0400788 /* Check the attribute flags */
Denis Ovsienkoe531d4a2011-09-24 13:20:43 +0400789 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
790 {
791 zlog (peer->log, LOG_ERR,
792 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
793 bgp_notify_send_with_data (peer,
794 BGP_NOTIFY_UPDATE_ERR,
795 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
796 startp, total);
797 return NULL;
798 }
799
Chris Hallcddb8112010-08-09 22:31:37 +0400800 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
801 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000802
Chris Hallcddb8112010-08-09 22:31:37 +0400803 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000804 {
Chris Hallcddb8112010-08-09 22:31:37 +0400805 const char* path_type ;
Chris Hallcddb8112010-08-09 22:31:37 +0400806
807 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
808
809 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000810 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400811 "%s attribute flag isn't transitive %d", path_type, flag) ;
812
813 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
814 zlog (peer->log, LOG_ERR,
815 "%s attribute flag must %sbe optional %d", path_type,
816 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
817
paul718e3742002-12-13 20:15:29 +0000818 bgp_notify_send_with_data (peer,
819 BGP_NOTIFY_UPDATE_ERR,
820 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
821 startp, total);
paul718e3742002-12-13 20:15:29 +0000822
Chris Hallcddb8112010-08-09 22:31:37 +0400823 return NULL ;
824 } ;
825
826 /* Parse the AS_PATH/AS4_PATH body.
827 *
828 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
829 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000830 */
Chris Hallcddb8112010-08-09 22:31:37 +0400831 asp = aspath_parse (peer->ibuf, length,
832 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000833
Chris Hallcddb8112010-08-09 22:31:37 +0400834 if (asp != NULL)
835 {
836 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
837 : BGP_ATTR_AS_PATH) ;
838 }
839 else
paul718e3742002-12-13 20:15:29 +0000840 {
841 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400842
843 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000844 bgp_notify_send (peer,
845 BGP_NOTIFY_UPDATE_ERR,
846 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400847 } ;
paul718e3742002-12-13 20:15:29 +0000848
Chris Hallcddb8112010-08-09 22:31:37 +0400849 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000850}
851
852static int bgp_attr_aspath_check( struct peer *peer,
853 struct attr *attr)
854{
855 /* These checks were part of bgp_attr_aspath, but with
856 * as4 we should to check aspath things when
857 * aspath synthesizing with as4_path has already taken place.
858 * Otherwise we check ASPATH and use the synthesized thing, and that is
859 * not right.
860 * So do the checks later, i.e. here
861 */
862 struct bgp *bgp = peer->bgp;
863 struct aspath *aspath;
864
paul718e3742002-12-13 20:15:29 +0000865 bgp = peer->bgp;
866
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300867 /* Confederation sanity check. */
868 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
869 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
870 {
871 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
872 bgp_notify_send (peer,
873 BGP_NOTIFY_UPDATE_ERR,
874 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
875 return -1;
876 }
877
paul718e3742002-12-13 20:15:29 +0000878 /* First AS check for EBGP. */
879 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
880 {
881 if (peer_sort (peer) == BGP_PEER_EBGP
882 && ! aspath_firstas_check (attr->aspath, peer->as))
883 {
884 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400885 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000886 bgp_notify_send (peer,
887 BGP_NOTIFY_UPDATE_ERR,
888 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
889 return -1;
890 }
891 }
892
893 /* local-as prepend */
894 if (peer->change_local_as &&
895 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
896 {
897 aspath = aspath_dup (attr->aspath);
898 aspath = aspath_add_seq (aspath, peer->change_local_as);
899 aspath_unintern (attr->aspath);
900 attr->aspath = aspath_intern (aspath);
901 }
902
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000903 return 0;
904
905}
906
paul718e3742002-12-13 20:15:29 +0000907/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000908static int
paul718e3742002-12-13 20:15:29 +0000909bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
910 struct attr *attr, u_char flag, u_char *startp)
911{
912 bgp_size_t total;
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400913 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000914
915 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
916
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400917 /* Flags check. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400918 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400919 {
920 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
921 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
922 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
923 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
924 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
925 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
926 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
927 return -1;
928 }
paul718e3742002-12-13 20:15:29 +0000929
930 /* Check nexthop attribute length. */
931 if (length != 4)
932 {
933 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
934 length);
935
936 bgp_notify_send_with_data (peer,
937 BGP_NOTIFY_UPDATE_ERR,
938 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
939 startp, total);
940 return -1;
941 }
942
Denis Ovsienko3eca6f02011-09-22 12:48:14 +0400943 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
944 attribute must result in a NOTIFICATION message (this is implemented below).
945 At the same time, semantically incorrect NEXT_HOP is more likely to be just
946 logged locally (this is implemented somewhere else). The UPDATE message
947 gets ignored in any of these cases. */
948 nexthop_n = stream_get_ipv4 (peer->ibuf);
949 nexthop_h = ntohl (nexthop_n);
950 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
951 {
952 char buf[INET_ADDRSTRLEN];
953 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
954 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
955 bgp_notify_send_with_data (peer,
956 BGP_NOTIFY_UPDATE_ERR,
957 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
958 startp, total);
959 return -1;
960 }
961
962 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +0000963 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
964
965 return 0;
966}
967
968/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000969static int
paul718e3742002-12-13 20:15:29 +0000970bgp_attr_med (struct peer *peer, bgp_size_t length,
971 struct attr *attr, u_char flag, u_char *startp)
972{
973 bgp_size_t total;
974
975 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
976
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400977 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +0400978 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +0400979 {
980 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
981 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
982 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
983 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
984 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
985 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
986 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
987 return -1;
988 }
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400989
paul718e3742002-12-13 20:15:29 +0000990 /* Length check. */
991 if (length != 4)
992 {
993 zlog (peer->log, LOG_ERR,
994 "MED attribute length isn't four [%d]", length);
995
996 bgp_notify_send_with_data (peer,
997 BGP_NOTIFY_UPDATE_ERR,
998 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
999 startp, total);
1000 return -1;
1001 }
1002
1003 attr->med = stream_getl (peer->ibuf);
1004
1005 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1006
1007 return 0;
1008}
1009
1010/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001011static int
paul718e3742002-12-13 20:15:29 +00001012bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001013 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001014{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001015 bgp_size_t total;
1016
1017 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1018 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001019 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001020 {
1021 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1022 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1023 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1024 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1025 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1026 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1027 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1028 return -1;
1029 }
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001030 /* Length check. */
1031 if (length != 4)
1032 {
1033 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
1034 bgp_notify_send_with_data (peer,
1035 BGP_NOTIFY_UPDATE_ERR,
1036 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1037 startp, total);
1038 return -1;
1039 }
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001040
paul718e3742002-12-13 20:15:29 +00001041 /* If it is contained in an UPDATE message that is received from an
1042 external peer, then this attribute MUST be ignored by the
1043 receiving speaker. */
1044 if (peer_sort (peer) == BGP_PEER_EBGP)
1045 {
paul9985f832005-02-09 15:51:56 +00001046 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001047 return 0;
1048 }
1049
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001050 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001051
1052 /* Set atomic aggregate flag. */
1053 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1054
1055 return 0;
1056}
1057
1058/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001059static int
paul718e3742002-12-13 20:15:29 +00001060bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001061 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001062{
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001063 bgp_size_t total;
1064
1065 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1066 /* Flag checks. */
Denis Ovsienko566941f2011-10-12 13:54:21 +04001067 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienko395ec7f2011-09-27 15:47:25 +04001068 {
1069 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1070 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1071 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1072 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1073 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1074 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1075 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1076 return -1;
1077 }
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001078
1079 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001080 if (length != 0)
1081 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001082 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
1083 bgp_notify_send_with_data (peer,
1084 BGP_NOTIFY_UPDATE_ERR,
1085 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1086 startp, total);
paul718e3742002-12-13 20:15:29 +00001087 return -1;
1088 }
1089
1090 /* Set atomic aggregate flag. */
1091 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1092
1093 return 0;
1094}
1095
1096/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001097static int
paul718e3742002-12-13 20:15:29 +00001098bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001099 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001100{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001101 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001102 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001103 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001104
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001105 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001106 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1107 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1108 wantedlen = 8;
1109
1110 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001111 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001112 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
1113 bgp_notify_send_with_data (peer,
1114 BGP_NOTIFY_UPDATE_ERR,
1115 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1116 startp, total);
paul718e3742002-12-13 20:15:29 +00001117 return -1;
1118 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001119
1120 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1121 attre->aggregator_as = stream_getl (peer->ibuf);
1122 else
1123 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001124 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001125
1126 /* Set atomic aggregate flag. */
1127 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1128
1129 return 0;
1130}
1131
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001132/* New Aggregator attribute */
1133static int
1134bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1135 struct attr *attr, as_t *as4_aggregator_as,
1136 struct in_addr *as4_aggregator_addr)
1137{
1138 if (length != 8)
1139 {
1140 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1141
1142 bgp_notify_send (peer,
1143 BGP_NOTIFY_UPDATE_ERR,
1144 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1145 return -1;
1146 }
1147 *as4_aggregator_as = stream_getl (peer->ibuf);
1148 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1149
1150 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1151
1152 return 0;
1153}
1154
1155/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1156 */
1157static int
1158bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1159 struct aspath *as4_path, as_t as4_aggregator,
1160 struct in_addr *as4_aggregator_addr)
1161{
1162 int ignore_as4_path = 0;
1163 struct aspath *newpath;
1164 struct attr_extra *attre = attr->extra;
1165
1166 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1167 {
1168 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1169 * if given.
1170 * It is worth a warning though, because the peer really
1171 * should not send them
1172 */
1173 if (BGP_DEBUG(as4, AS4))
1174 {
1175 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1176 zlog_debug ("[AS4] %s %s AS4_PATH",
1177 peer->host, "AS4 capable peer, yet it sent");
1178
1179 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1180 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1181 peer->host, "AS4 capable peer, yet it sent");
1182 }
1183
1184 return 0;
1185 }
1186
1187 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1188 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1189 {
1190 /* Hu? This is not supposed to happen at all!
1191 * got as4_path and no aspath,
1192 * This should already
1193 * have been handled by 'well known attributes missing'
1194 * But... yeah, paranoia
1195 * Take this as a "malformed attribute"
1196 */
1197 zlog (peer->log, LOG_ERR,
1198 "%s BGP not AS4 capable peer sent AS4_PATH but"
1199 " no AS_PATH, cant do anything here", peer->host);
1200 bgp_notify_send (peer,
1201 BGP_NOTIFY_UPDATE_ERR,
1202 BGP_NOTIFY_UPDATE_MAL_ATTR);
1203 return -1;
1204 }
1205
1206 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1207 * because that may override AS4_PATH
1208 */
1209 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1210 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001211 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1212 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001213 assert (attre);
1214
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001215 /* received both.
1216 * if the as_number in aggregator is not AS_TRANS,
1217 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1218 * and the Aggregator shall be taken as
1219 * info on the aggregating node, and the AS_PATH
1220 * shall be taken as the AS_PATH
1221 * otherwise
1222 * the Aggregator shall be ignored and the
1223 * AS4_AGGREGATOR shall be taken as the
1224 * Aggregating node and the AS_PATH is to be
1225 * constructed "as in all other cases"
1226 */
1227 if ( attre->aggregator_as != BGP_AS_TRANS )
1228 {
1229 /* ignore */
1230 if ( BGP_DEBUG(as4, AS4))
1231 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1232 " send AGGREGATOR != AS_TRANS and"
1233 " AS4_AGGREGATOR, so ignore"
1234 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1235 ignore_as4_path = 1;
1236 }
1237 else
1238 {
1239 /* "New_aggregator shall be taken as aggregator" */
1240 attre->aggregator_as = as4_aggregator;
1241 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1242 }
1243 }
1244 else
1245 {
1246 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1247 * That is bogus - but reading the conditions
1248 * we have to handle AS4_AGGREGATOR as if it were
1249 * AGGREGATOR in that case
1250 */
1251 if ( BGP_DEBUG(as4, AS4))
1252 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1253 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1254 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001255 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001256 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1257 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1258 }
1259 }
1260
1261 /* need to reconcile NEW_AS_PATH and AS_PATH */
1262 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1263 {
1264 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1265 aspath_unintern (attr->aspath);
1266 attr->aspath = aspath_intern (newpath);
1267 }
1268 return 0;
1269}
1270
paul718e3742002-12-13 20:15:29 +00001271/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001272static int
paul718e3742002-12-13 20:15:29 +00001273bgp_attr_community (struct peer *peer, bgp_size_t length,
1274 struct attr *attr, u_char flag)
1275{
1276 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001277 {
1278 attr->community = NULL;
1279 return 0;
1280 }
Paul Jakmafc097162010-12-05 17:17:26 +00001281
1282 attr->community =
1283 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1284
1285 /* XXX: fix community_parse to use stream API and remove this */
1286 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001287
Paul Jakmafc097162010-12-05 17:17:26 +00001288 if (!attr->community)
1289 return -1;
1290
paul718e3742002-12-13 20:15:29 +00001291 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1292
1293 return 0;
1294}
1295
1296/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001297static int
paul718e3742002-12-13 20:15:29 +00001298bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienko5de17192011-09-30 15:08:54 +04001299 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001300{
Denis Ovsienko5de17192011-09-30 15:08:54 +04001301 bgp_size_t total;
1302
1303 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1304 /* Flag checks. */
1305 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1306 {
1307 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1308 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1309 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1310 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1311 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1312 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
1313 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1314 return -1;
1315 }
1316 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001317 if (length != 4)
1318 {
1319 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1320
1321 bgp_notify_send (peer,
1322 BGP_NOTIFY_UPDATE_ERR,
1323 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1324 return -1;
1325 }
1326
Paul Jakmafb982c22007-05-04 20:15:47 +00001327 (bgp_attr_extra_get (attr))->originator_id.s_addr
1328 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001329
1330 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1331
1332 return 0;
1333}
1334
1335/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001336static int
paul718e3742002-12-13 20:15:29 +00001337bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001338 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001339{
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001340 bgp_size_t total;
1341
1342 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1343 /* Flag checks. */
1344 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1345 {
1346 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1347 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1348 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1349 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1350 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1351 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
1352 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1353 return -1;
1354 }
paul718e3742002-12-13 20:15:29 +00001355 /* Check length. */
1356 if (length % 4)
1357 {
1358 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1359
1360 bgp_notify_send (peer,
1361 BGP_NOTIFY_UPDATE_ERR,
1362 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1363 return -1;
1364 }
1365
Paul Jakmafb982c22007-05-04 20:15:47 +00001366 (bgp_attr_extra_get (attr))->cluster
1367 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001368
paul9985f832005-02-09 15:51:56 +00001369 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001370
1371 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1372
1373 return 0;
1374}
1375
1376/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001377int
paul718e3742002-12-13 20:15:29 +00001378bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1379 struct bgp_nlri *mp_update)
1380{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001381 afi_t afi;
1382 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001383 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001384 size_t start;
paul718e3742002-12-13 20:15:29 +00001385 int ret;
1386 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001387 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001388
1389 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001390 s = BGP_INPUT(peer);
1391 start = stream_get_getp(s);
1392
1393 /* safe to read statically sized header? */
1394#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001395#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001396 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001397 {
1398 zlog_info ("%s: %s sent invalid length, %lu",
1399 __func__, peer->host, (unsigned long)length);
1400 return -1;
1401 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001402
paul718e3742002-12-13 20:15:29 +00001403 /* Load AFI, SAFI. */
1404 afi = stream_getw (s);
1405 safi = stream_getc (s);
1406
1407 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001408 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001409
Paul Jakma03292802008-06-07 20:37:10 +00001410 if (LEN_LEFT < attre->mp_nexthop_len)
1411 {
1412 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1413 __func__, peer->host, attre->mp_nexthop_len);
1414 return -1;
1415 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001416
paul718e3742002-12-13 20:15:29 +00001417 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001418 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001419 {
1420 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001421 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001422 /* Probably needed for RFC 2283 */
1423 if (attr->nexthop.s_addr == 0)
1424 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001425 break;
1426 case 12:
1427 {
1428 u_int32_t rd_high;
1429 u_int32_t rd_low;
1430
1431 rd_high = stream_getl (s);
1432 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001433 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001434 }
1435 break;
1436#ifdef HAVE_IPV6
1437 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001438 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001439 break;
1440 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001441 stream_get (&attre->mp_nexthop_global, s, 16);
1442 stream_get (&attre->mp_nexthop_local, s, 16);
1443 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001444 {
1445 char buf1[INET6_ADDRSTRLEN];
1446 char buf2[INET6_ADDRSTRLEN];
1447
1448 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001449 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 +00001450 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001451 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001452 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001453 buf2, INET6_ADDRSTRLEN));
1454
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001456 }
1457 break;
1458#endif /* HAVE_IPV6 */
1459 default:
Paul Jakma03292802008-06-07 20:37:10 +00001460 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1461 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001462 return -1;
paul718e3742002-12-13 20:15:29 +00001463 }
1464
Paul Jakma03292802008-06-07 20:37:10 +00001465 if (!LEN_LEFT)
1466 {
1467 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1468 __func__, peer->host);
1469 return -1;
1470 }
paul718e3742002-12-13 20:15:29 +00001471
Paul Jakma6e4ab122007-04-10 19:36:48 +00001472 {
1473 u_char val;
1474 if ((val = stream_getc (s)))
1475 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1476 peer->host, val);
1477 }
1478
1479 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001480 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001481 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001482 {
1483 zlog_info ("%s: (%s) Failed to read NLRI",
1484 __func__, peer->host);
1485 return -1;
1486 }
paul718e3742002-12-13 20:15:29 +00001487
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001488 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001489 {
1490 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001491 if (ret < 0)
1492 {
1493 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1494 __func__, peer->host);
1495 return -1;
1496 }
paul718e3742002-12-13 20:15:29 +00001497 }
1498
1499 mp_update->afi = afi;
1500 mp_update->safi = safi;
1501 mp_update->nlri = stream_pnt (s);
1502 mp_update->length = nlri_len;
1503
paul9985f832005-02-09 15:51:56 +00001504 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001505
1506 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001507#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001508}
1509
1510/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001511int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001512bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001513 struct bgp_nlri *mp_withdraw)
1514{
1515 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001516 afi_t afi;
1517 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001518 u_int16_t withdraw_len;
1519 int ret;
1520
1521 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001522
1523#define BGP_MP_UNREACH_MIN_SIZE 3
1524 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1525 return -1;
1526
paul718e3742002-12-13 20:15:29 +00001527 afi = stream_getw (s);
1528 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001529
1530 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001531
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001532 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001533 {
1534 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1535 if (ret < 0)
1536 return -1;
1537 }
1538
1539 mp_withdraw->afi = afi;
1540 mp_withdraw->safi = safi;
1541 mp_withdraw->nlri = stream_pnt (s);
1542 mp_withdraw->length = withdraw_len;
1543
paul9985f832005-02-09 15:51:56 +00001544 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001545
1546 return 0;
1547}
1548
1549/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001550static int
paul718e3742002-12-13 20:15:29 +00001551bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1552 struct attr *attr, u_char flag)
1553{
1554 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001555 {
1556 if (attr->extra)
1557 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001558 /* Empty extcomm doesn't seem to be invalid per se */
1559 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001560 }
Paul Jakmafc097162010-12-05 17:17:26 +00001561
1562 (bgp_attr_extra_get (attr))->ecommunity =
1563 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1564 /* XXX: fix ecommunity_parse to use stream API */
1565 stream_forward_getp (peer->ibuf, length);
1566
1567 if (!attr->extra->ecommunity)
1568 return -1;
1569
paul718e3742002-12-13 20:15:29 +00001570 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1571
1572 return 0;
1573}
1574
1575/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001576static int
paul718e3742002-12-13 20:15:29 +00001577bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1578 u_char type, bgp_size_t length, u_char *startp)
1579{
1580 bgp_size_t total;
1581 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001582 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001583
hassof4184462005-02-01 20:13:16 +00001584 if (BGP_DEBUG (normal, NORMAL))
1585 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1586 peer->host, type, length);
1587
paul718e3742002-12-13 20:15:29 +00001588 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001589 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001590 "Unknown attribute type %d length %d is received", type, length);
1591
1592 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001593 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001594
1595 /* Adjest total length to include type and length. */
1596 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1597
1598 /* If any of the mandatory well-known attributes are not recognized,
1599 then the Error Subcode is set to Unrecognized Well-known
1600 Attribute. The Data field contains the unrecognized attribute
1601 (type, length and value). */
1602 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1603 {
1604 /* Adjust startp to do not include flag value. */
1605 bgp_notify_send_with_data (peer,
1606 BGP_NOTIFY_UPDATE_ERR,
1607 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1608 startp, total);
1609 return -1;
1610 }
1611
1612 /* Unrecognized non-transitive optional attributes must be quietly
1613 ignored and not passed along to other BGP peers. */
1614 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1615 return 0;
1616
1617 /* If a path with recognized transitive optional attribute is
1618 accepted and passed along to other BGP peers and the Partial bit
1619 in the Attribute Flags octet is set to 1 by some previous AS, it
1620 is not set back to 0 by the current AS. */
1621 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1622
1623 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001624 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001625 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001626
Paul Jakmafb982c22007-05-04 20:15:47 +00001627 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001628
1629 if (transit->val)
1630 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1631 transit->length + total);
1632 else
1633 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1634
1635 memcpy (transit->val + transit->length, startp, total);
1636 transit->length += total;
1637
1638 return 0;
1639}
1640
1641/* Read attribute of update packet. This function is called from
1642 bgp_update() in bgpd.c. */
1643int
1644bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1645 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1646{
1647 int ret;
1648 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001649 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001650 bgp_size_t length;
1651 u_char *startp, *endp;
1652 u_char *attr_endp;
1653 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001654 /* we need the as4_path only until we have synthesized the as_path with it */
1655 /* same goes for as4_aggregator */
1656 struct aspath *as4_path = NULL;
1657 as_t as4_aggregator = 0;
1658 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001659
1660 /* Initialize bitmap. */
1661 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1662
1663 /* End pointer of BGP attribute. */
1664 endp = BGP_INPUT_PNT (peer) + size;
1665
1666 /* Get attributes to the end of attribute length. */
1667 while (BGP_INPUT_PNT (peer) < endp)
1668 {
1669 /* Check remaining length check.*/
1670 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1671 {
gdtc29fdba2004-12-09 14:46:46 +00001672 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001673 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001674 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001675 peer->host,
1676 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001677
1678 bgp_notify_send (peer,
1679 BGP_NOTIFY_UPDATE_ERR,
1680 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1681 return -1;
1682 }
1683
1684 /* Fetch attribute flag and type. */
1685 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001686 /* "The lower-order four bits of the Attribute Flags octet are
1687 unused. They MUST be zero when sent and MUST be ignored when
1688 received." */
1689 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001690 type = stream_getc (BGP_INPUT (peer));
1691
Paul Jakma370b64a2007-12-22 16:49:52 +00001692 /* Check whether Extended-Length applies and is in bounds */
1693 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1694 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1695 {
1696 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001697 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001698 peer->host,
1699 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1700
1701 bgp_notify_send (peer,
1702 BGP_NOTIFY_UPDATE_ERR,
1703 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1704 return -1;
1705 }
1706
paul718e3742002-12-13 20:15:29 +00001707 /* Check extended attribue length bit. */
1708 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1709 length = stream_getw (BGP_INPUT (peer));
1710 else
1711 length = stream_getc (BGP_INPUT (peer));
1712
1713 /* If any attribute appears more than once in the UPDATE
1714 message, then the Error Subcode is set to Malformed Attribute
1715 List. */
1716
1717 if (CHECK_BITMAP (seen, type))
1718 {
1719 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001720 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001721 peer->host, type);
1722
1723 bgp_notify_send (peer,
1724 BGP_NOTIFY_UPDATE_ERR,
1725 BGP_NOTIFY_UPDATE_MAL_ATTR);
1726 return -1;
1727 }
1728
1729 /* Set type to bitmap to check duplicate attribute. `type' is
1730 unsigned char so it never overflow bitmap range. */
1731
1732 SET_BITMAP (seen, type);
1733
1734 /* Overflow check. */
1735 attr_endp = BGP_INPUT_PNT (peer) + length;
1736
1737 if (attr_endp > endp)
1738 {
1739 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001740 "%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 +00001741 bgp_notify_send (peer,
1742 BGP_NOTIFY_UPDATE_ERR,
1743 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1744 return -1;
1745 }
1746
1747 /* OK check attribute and store it's value. */
1748 switch (type)
1749 {
1750 case BGP_ATTR_ORIGIN:
1751 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1752 break;
1753 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001754 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1755 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001756 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001757 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001758 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1759 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001760 break;
paul718e3742002-12-13 20:15:29 +00001761 case BGP_ATTR_NEXT_HOP:
1762 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1763 break;
1764 case BGP_ATTR_MULTI_EXIT_DISC:
1765 ret = bgp_attr_med (peer, length, attr, flag, startp);
1766 break;
1767 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001768 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001769 break;
1770 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001771 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001772 break;
1773 case BGP_ATTR_AGGREGATOR:
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001774 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001775 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001776 case BGP_ATTR_AS4_AGGREGATOR:
1777 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1778 break;
paul718e3742002-12-13 20:15:29 +00001779 case BGP_ATTR_COMMUNITIES:
1780 ret = bgp_attr_community (peer, length, attr, flag);
1781 break;
1782 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienko5de17192011-09-30 15:08:54 +04001783 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001784 break;
1785 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001786 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001787 break;
1788 case BGP_ATTR_MP_REACH_NLRI:
1789 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1790 break;
1791 case BGP_ATTR_MP_UNREACH_NLRI:
1792 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1793 break;
1794 case BGP_ATTR_EXT_COMMUNITIES:
1795 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1796 break;
1797 default:
1798 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1799 break;
1800 }
1801
1802 /* If error occured immediately return to the caller. */
1803 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001804 {
1805 zlog (peer->log, LOG_WARNING,
1806 "%s: Attribute %s, parse error",
1807 peer->host,
1808 LOOKUP (attr_str, type));
1809 bgp_notify_send (peer,
1810 BGP_NOTIFY_UPDATE_ERR,
1811 BGP_NOTIFY_UPDATE_MAL_ATTR);
1812 return ret;
1813 }
paul718e3742002-12-13 20:15:29 +00001814
1815 /* Check the fetched length. */
1816 if (BGP_INPUT_PNT (peer) != attr_endp)
1817 {
1818 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001819 "%s: BGP attribute %s, fetch error",
1820 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001821 bgp_notify_send (peer,
1822 BGP_NOTIFY_UPDATE_ERR,
1823 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1824 return -1;
1825 }
1826 }
1827
1828 /* Check final read pointer is same as end pointer. */
1829 if (BGP_INPUT_PNT (peer) != endp)
1830 {
1831 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001832 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001833 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001834 bgp_notify_send (peer,
1835 BGP_NOTIFY_UPDATE_ERR,
1836 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1837 return -1;
1838 }
1839
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001840 /*
1841 * At this place we can see whether we got AS4_PATH and/or
1842 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1843 * We can not do this before we've read all attributes because
1844 * the as4 handling does not say whether AS4_PATH has to be sent
1845 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1846 * in relationship to AGGREGATOR.
1847 * So, to be defensive, we are not relying on any order and read
1848 * all attributes first, including these 32bit ones, and now,
1849 * afterwards, we look what and if something is to be done for as4.
1850 */
1851 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1852 as4_aggregator, &as4_aggregator_addr))
1853 return -1;
1854
1855 /* At this stage, we have done all fiddling with as4, and the
1856 * resulting info is in attr->aggregator resp. attr->aspath
1857 * so we can chuck as4_aggregator and as4_path alltogether in
1858 * order to save memory
1859 */
1860 if ( as4_path )
1861 {
1862 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1863 as4_path = NULL;
1864 /* The flag that we got this is still there, but that does not
1865 * do any trouble
1866 */
1867 }
1868 /*
1869 * The "rest" of the code does nothing with as4_aggregator.
1870 * there is no memory attached specifically which is not part
1871 * of the attr.
1872 * so ignoring just means do nothing.
1873 */
1874 /*
1875 * Finally do the checks on the aspath we did not do yet
1876 * because we waited for a potentially synthesized aspath.
1877 */
1878 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1879 {
1880 ret = bgp_attr_aspath_check( peer, attr );
1881 if ( ret < 0 )
1882 return ret;
1883 }
1884
paul718e3742002-12-13 20:15:29 +00001885 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001886 if (attr->extra && attr->extra->transit)
1887 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001888
1889 return 0;
1890}
1891
1892/* Well-known attribute check. */
1893int
1894bgp_attr_check (struct peer *peer, struct attr *attr)
1895{
1896 u_char type = 0;
1897
1898 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1899 type = BGP_ATTR_ORIGIN;
1900
1901 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1902 type = BGP_ATTR_AS_PATH;
1903
1904 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1905 type = BGP_ATTR_NEXT_HOP;
1906
1907 if (peer_sort (peer) == BGP_PEER_IBGP
1908 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1909 type = BGP_ATTR_LOCAL_PREF;
1910
1911 if (type)
1912 {
1913 zlog (peer->log, LOG_WARNING,
1914 "%s Missing well-known attribute %d.",
1915 peer->host, type);
1916 bgp_notify_send_with_data (peer,
1917 BGP_NOTIFY_UPDATE_ERR,
1918 BGP_NOTIFY_UPDATE_MISS_ATTR,
1919 &type, 1);
1920 return -1;
1921 }
1922 return 0;
1923}
1924
1925int stream_put_prefix (struct stream *, struct prefix *);
1926
1927/* Make attribute packet. */
1928bgp_size_t
1929bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1930 struct stream *s, struct attr *attr, struct prefix *p,
1931 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001932 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001933{
paulfe69a502005-09-10 16:55:02 +00001934 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001935 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001936 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001937 int send_as4_path = 0;
1938 int send_as4_aggregator = 0;
1939 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001940
1941 if (! bgp)
1942 bgp = bgp_get_default ();
1943
1944 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001945 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001946
1947 /* Origin attribute. */
1948 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1949 stream_putc (s, BGP_ATTR_ORIGIN);
1950 stream_putc (s, 1);
1951 stream_putc (s, attr->origin);
1952
1953 /* AS path attribute. */
1954
1955 /* If remote-peer is EBGP */
1956 if (peer_sort (peer) == BGP_PEER_EBGP
1957 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001958 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001959 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001960 {
1961 aspath = aspath_dup (attr->aspath);
1962
1963 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1964 {
1965 /* Strip the confed info, and then stuff our path CONFED_ID
1966 on the front */
1967 aspath = aspath_delete_confed_seq (aspath);
1968 aspath = aspath_add_seq (aspath, bgp->confed_id);
1969 }
1970 else
1971 {
1972 aspath = aspath_add_seq (aspath, peer->local_as);
1973 if (peer->change_local_as)
1974 aspath = aspath_add_seq (aspath, peer->change_local_as);
1975 }
1976 }
1977 else if (peer_sort (peer) == BGP_PEER_CONFED)
1978 {
1979 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1980 aspath = aspath_dup (attr->aspath);
1981 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1982 }
1983 else
1984 aspath = attr->aspath;
1985
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001986 /* If peer is not AS4 capable, then:
1987 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1988 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1989 * types are in it (i.e. exclude them if they are there)
1990 * AND do this only if there is at least one asnum > 65535 in the path!
1991 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1992 * all ASnums > 65535 to BGP_AS_TRANS
1993 */
paul718e3742002-12-13 20:15:29 +00001994
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001995 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1996 stream_putc (s, BGP_ATTR_AS_PATH);
1997 aspath_sizep = stream_get_endp (s);
1998 stream_putw (s, 0);
1999 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2000
2001 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2002 * in the path
2003 */
2004 if (!use32bit && aspath_has_as4 (aspath))
2005 send_as4_path = 1; /* we'll do this later, at the correct place */
2006
paul718e3742002-12-13 20:15:29 +00002007 /* Nexthop attribute. */
2008 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2009 {
2010 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2011 stream_putc (s, BGP_ATTR_NEXT_HOP);
2012 stream_putc (s, 4);
2013 if (safi == SAFI_MPLS_VPN)
2014 {
2015 if (attr->nexthop.s_addr == 0)
2016 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2017 else
2018 stream_put_ipv4 (s, attr->nexthop.s_addr);
2019 }
2020 else
2021 stream_put_ipv4 (s, attr->nexthop.s_addr);
2022 }
2023
2024 /* MED attribute. */
2025 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2026 {
2027 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2028 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2029 stream_putc (s, 4);
2030 stream_putl (s, attr->med);
2031 }
2032
2033 /* Local preference. */
2034 if (peer_sort (peer) == BGP_PEER_IBGP ||
2035 peer_sort (peer) == BGP_PEER_CONFED)
2036 {
2037 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2038 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2039 stream_putc (s, 4);
2040 stream_putl (s, attr->local_pref);
2041 }
2042
2043 /* Atomic aggregate. */
2044 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2045 {
2046 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2047 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2048 stream_putc (s, 0);
2049 }
2050
2051 /* Aggregator. */
2052 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2053 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002054 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002055
2056 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002057 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2058 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002059
2060 if (use32bit)
2061 {
2062 /* AS4 capable peer */
2063 stream_putc (s, 8);
2064 stream_putl (s, attr->extra->aggregator_as);
2065 }
2066 else
2067 {
2068 /* 2-byte AS peer */
2069 stream_putc (s, 6);
2070
2071 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2072 if ( attr->extra->aggregator_as > 65535 )
2073 {
2074 stream_putw (s, BGP_AS_TRANS);
2075
2076 /* we have to send AS4_AGGREGATOR, too.
2077 * we'll do that later in order to send attributes in ascending
2078 * order.
2079 */
2080 send_as4_aggregator = 1;
2081 }
2082 else
2083 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2084 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002085 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002086 }
2087
2088 /* Community attribute. */
2089 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2090 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2091 {
2092 if (attr->community->size * 4 > 255)
2093 {
2094 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2095 stream_putc (s, BGP_ATTR_COMMUNITIES);
2096 stream_putw (s, attr->community->size * 4);
2097 }
2098 else
2099 {
2100 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2101 stream_putc (s, BGP_ATTR_COMMUNITIES);
2102 stream_putc (s, attr->community->size * 4);
2103 }
2104 stream_put (s, attr->community->val, attr->community->size * 4);
2105 }
2106
2107 /* Route Reflector. */
2108 if (peer_sort (peer) == BGP_PEER_IBGP
2109 && from
2110 && peer_sort (from) == BGP_PEER_IBGP)
2111 {
2112 /* Originator ID. */
2113 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2114 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2115 stream_putc (s, 4);
2116
2117 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002118 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002119 else
2120 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002121
2122 /* Cluster list. */
2123 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2124 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2125
Paul Jakma9eda90c2007-08-30 13:36:17 +00002126 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002127 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002128 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002129 /* If this peer configuration's parent BGP has cluster_id. */
2130 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2131 stream_put_in_addr (s, &bgp->cluster_id);
2132 else
2133 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002134 stream_put (s, attr->extra->cluster->list,
2135 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002136 }
2137 else
2138 {
2139 stream_putc (s, 4);
2140 /* If this peer configuration's parent BGP has cluster_id. */
2141 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2142 stream_put_in_addr (s, &bgp->cluster_id);
2143 else
2144 stream_put_in_addr (s, &bgp->router_id);
2145 }
2146 }
2147
2148#ifdef HAVE_IPV6
2149 /* If p is IPv6 address put it into attribute. */
2150 if (p->family == AF_INET6)
2151 {
2152 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002153 struct attr_extra *attre = attr->extra;
2154
2155 assert (attr->extra);
2156
paul718e3742002-12-13 20:15:29 +00002157 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2158 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002159 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002160 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002161 stream_putw (s, AFI_IP6); /* AFI */
2162 stream_putc (s, safi); /* SAFI */
2163
Paul Jakmafb982c22007-05-04 20:15:47 +00002164 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002165
Paul Jakmafb982c22007-05-04 20:15:47 +00002166 if (attre->mp_nexthop_len == 16)
2167 stream_put (s, &attre->mp_nexthop_global, 16);
2168 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002169 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002170 stream_put (s, &attre->mp_nexthop_global, 16);
2171 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002172 }
2173
2174 /* SNPA */
2175 stream_putc (s, 0);
2176
paul718e3742002-12-13 20:15:29 +00002177 /* Prefix write. */
2178 stream_put_prefix (s, p);
2179
2180 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002181 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002182 }
2183#endif /* HAVE_IPV6 */
2184
2185 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2186 {
2187 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002188
2189 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2190 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002191 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002192 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002193 stream_putw (s, AFI_IP); /* AFI */
2194 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2195
2196 stream_putc (s, 4);
2197 stream_put_ipv4 (s, attr->nexthop.s_addr);
2198
2199 /* SNPA */
2200 stream_putc (s, 0);
2201
paul718e3742002-12-13 20:15:29 +00002202 /* Prefix write. */
2203 stream_put_prefix (s, p);
2204
2205 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002206 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002207 }
2208
2209 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2210 {
2211 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002212
2213 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2214 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002215 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002216 stream_putc (s, 0); /* Length of this attribute. */
2217 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002218 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002219
2220 stream_putc (s, 12);
2221 stream_putl (s, 0);
2222 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002223 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002224
2225 /* SNPA */
2226 stream_putc (s, 0);
2227
paul718e3742002-12-13 20:15:29 +00002228 /* Tag, RD, Prefix write. */
2229 stream_putc (s, p->prefixlen + 88);
2230 stream_put (s, tag, 3);
2231 stream_put (s, prd->val, 8);
2232 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2233
2234 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002235 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002236 }
2237
2238 /* Extended Communities attribute. */
2239 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2240 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2241 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002242 struct attr_extra *attre = attr->extra;
2243
2244 assert (attre);
2245
2246 if (peer_sort (peer) == BGP_PEER_IBGP
2247 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002248 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002249 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002250 {
2251 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2252 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002253 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002254 }
2255 else
2256 {
2257 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2258 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002259 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002260 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002261 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002262 }
2263 else
2264 {
paul5228ad22004-06-04 17:58:18 +00002265 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002266 int tbit;
2267 int ecom_tr_size = 0;
2268 int i;
2269
Paul Jakmafb982c22007-05-04 20:15:47 +00002270 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002271 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002272 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002273 tbit = *pnt;
2274
2275 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2276 continue;
2277
2278 ecom_tr_size++;
2279 }
2280
2281 if (ecom_tr_size)
2282 {
2283 if (ecom_tr_size * 8 > 255)
2284 {
2285 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2286 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2287 stream_putw (s, ecom_tr_size * 8);
2288 }
2289 else
2290 {
2291 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2292 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2293 stream_putc (s, ecom_tr_size * 8);
2294 }
2295
Paul Jakmafb982c22007-05-04 20:15:47 +00002296 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002297 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002298 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002299 tbit = *pnt;
2300
2301 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2302 continue;
2303
2304 stream_put (s, pnt, 8);
2305 }
2306 }
paul718e3742002-12-13 20:15:29 +00002307 }
paul718e3742002-12-13 20:15:29 +00002308 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002309
2310 if ( send_as4_path )
2311 {
2312 /* If the peer is NOT As4 capable, AND */
2313 /* there are ASnums > 65535 in path THEN
2314 * give out AS4_PATH */
2315
2316 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2317 * path segments!
2318 * Hm, I wonder... confederation things *should* only be at
2319 * the beginning of an aspath, right? Then we should use
2320 * aspath_delete_confed_seq for this, because it is already
2321 * there! (JK)
2322 * Folks, talk to me: what is reasonable here!?
2323 */
2324 aspath = aspath_delete_confed_seq (aspath);
2325
2326 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2327 stream_putc (s, BGP_ATTR_AS4_PATH);
2328 aspath_sizep = stream_get_endp (s);
2329 stream_putw (s, 0);
2330 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2331 }
2332
2333 if (aspath != attr->aspath)
2334 aspath_free (aspath);
2335
2336 if ( send_as4_aggregator )
2337 {
2338 assert (attr->extra);
2339
2340 /* send AS4_AGGREGATOR, at this place */
2341 /* this section of code moved here in order to ensure the correct
2342 * *ascending* order of attributes
2343 */
2344 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2345 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2346 stream_putc (s, 8);
2347 stream_putl (s, attr->extra->aggregator_as);
2348 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2349 }
Paul Jakma41367172007-08-06 15:24:51 +00002350
paul718e3742002-12-13 20:15:29 +00002351 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002352 if (attr->extra && attr->extra->transit)
2353 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002354
2355 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002356 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002357}
2358
2359bgp_size_t
2360bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2361 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002362 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002363{
2364 unsigned long cp;
2365 unsigned long attrlen_pnt;
2366 bgp_size_t size;
2367
paul9985f832005-02-09 15:51:56 +00002368 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002369
2370 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2371 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2372
paul9985f832005-02-09 15:51:56 +00002373 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002374 stream_putc (s, 0); /* Length of this attribute. */
2375
2376 stream_putw (s, family2afi (p->family));
2377
2378 if (safi == SAFI_MPLS_VPN)
2379 {
2380 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002381 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002382
2383 /* prefix. */
2384 stream_putc (s, p->prefixlen + 88);
2385 stream_put (s, tag, 3);
2386 stream_put (s, prd->val, 8);
2387 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2388 }
2389 else
2390 {
2391 /* SAFI */
2392 stream_putc (s, safi);
2393
2394 /* prefix */
2395 stream_put_prefix (s, p);
2396 }
2397
2398 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002399 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002400 stream_putc_at (s, attrlen_pnt, size);
2401
paul9985f832005-02-09 15:51:56 +00002402 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002403}
2404
2405/* Initialization of attribute. */
2406void
paulfe69a502005-09-10 16:55:02 +00002407bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002408{
paul718e3742002-12-13 20:15:29 +00002409 aspath_init ();
2410 attrhash_init ();
2411 community_init ();
2412 ecommunity_init ();
2413 cluster_init ();
2414 transit_init ();
2415}
2416
Chris Caputo228da422009-07-18 05:44:03 +00002417void
2418bgp_attr_finish (void)
2419{
2420 aspath_finish ();
2421 attrhash_finish ();
2422 community_finish ();
2423 ecommunity_finish ();
2424 cluster_finish ();
2425 transit_finish ();
2426}
2427
paul718e3742002-12-13 20:15:29 +00002428/* Make attribute packet. */
2429void
paula3845922003-10-18 01:30:50 +00002430bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2431 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002432{
2433 unsigned long cp;
2434 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002435 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002436 struct aspath *aspath;
2437
2438 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002439 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002440
2441 /* Place holder of length. */
2442 stream_putw (s, 0);
2443
2444 /* Origin attribute. */
2445 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2446 stream_putc (s, BGP_ATTR_ORIGIN);
2447 stream_putc (s, 1);
2448 stream_putc (s, attr->origin);
2449
2450 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002451
2452 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2453 stream_putc (s, BGP_ATTR_AS_PATH);
2454 aspath_lenp = stream_get_endp (s);
2455 stream_putw (s, 0);
2456
2457 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002458
2459 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002460 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2461 if(prefix != NULL
2462#ifdef HAVE_IPV6
2463 && prefix->family != AF_INET6
2464#endif /* HAVE_IPV6 */
2465 )
2466 {
2467 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2468 stream_putc (s, BGP_ATTR_NEXT_HOP);
2469 stream_putc (s, 4);
2470 stream_put_ipv4 (s, attr->nexthop.s_addr);
2471 }
paul718e3742002-12-13 20:15:29 +00002472
2473 /* MED attribute. */
2474 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2475 {
2476 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2477 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2478 stream_putc (s, 4);
2479 stream_putl (s, attr->med);
2480 }
2481
2482 /* Local preference. */
2483 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2484 {
2485 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2486 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2487 stream_putc (s, 4);
2488 stream_putl (s, attr->local_pref);
2489 }
2490
2491 /* Atomic aggregate. */
2492 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2493 {
2494 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2495 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2496 stream_putc (s, 0);
2497 }
2498
2499 /* Aggregator. */
2500 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2501 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002502 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002503 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2504 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002505 stream_putc (s, 8);
2506 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002507 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002508 }
2509
2510 /* Community attribute. */
2511 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2512 {
2513 if (attr->community->size * 4 > 255)
2514 {
2515 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2516 stream_putc (s, BGP_ATTR_COMMUNITIES);
2517 stream_putw (s, attr->community->size * 4);
2518 }
2519 else
2520 {
2521 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2522 stream_putc (s, BGP_ATTR_COMMUNITIES);
2523 stream_putc (s, attr->community->size * 4);
2524 }
2525 stream_put (s, attr->community->val, attr->community->size * 4);
2526 }
2527
paula3845922003-10-18 01:30:50 +00002528#ifdef HAVE_IPV6
2529 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002530 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2531 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002532 {
2533 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002534 struct attr_extra *attre = attr->extra;
2535
paula3845922003-10-18 01:30:50 +00002536 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2537 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002538 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002539
2540 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002541 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002542 stream_putw(s, AFI_IP6); /* AFI */
2543 stream_putc(s, SAFI_UNICAST); /* SAFI */
2544
2545 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002546 stream_putc(s, attre->mp_nexthop_len);
2547 stream_put(s, &attre->mp_nexthop_global, 16);
2548 if (attre->mp_nexthop_len == 32)
2549 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002550
2551 /* SNPA */
2552 stream_putc(s, 0);
2553
2554 /* Prefix */
2555 stream_put_prefix(s, prefix);
2556
2557 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002558 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002559 }
2560#endif /* HAVE_IPV6 */
2561
paul718e3742002-12-13 20:15:29 +00002562 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002563 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002564 stream_putw_at (s, cp, len);
2565}