blob: 7c94f7e041fa9c6c7bb11d1ce974a65889fa61a3 [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,
Denis Ovsienko3062d2d2011-10-18 15:27:21 +0400816 CHECK_FLAG (require, BGP_ATTR_FLAG_OPTIONAL) ? "" : "not ", flag);
Chris Hallcddb8112010-08-09 22:31:37 +0400817
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);
Denis Ovsienko12da1a12011-10-22 22:11:31 +04001106 /* Flags check. */
1107 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1108 {
1109 zlog (peer->log, LOG_ERR,
1110 "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag);
1111 bgp_notify_send_with_data (peer,
1112 BGP_NOTIFY_UPDATE_ERR,
1113 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1114 startp, total);
1115 return -1;
1116 }
1117 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1118 {
1119 zlog (peer->log, LOG_ERR,
1120 "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag);
1121 bgp_notify_send_with_data (peer,
1122 BGP_NOTIFY_UPDATE_ERR,
1123 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1124 startp, total);
1125 return -1;
1126 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001127 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1128 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1129 wantedlen = 8;
1130
1131 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001132 {
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001133 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
1134 bgp_notify_send_with_data (peer,
1135 BGP_NOTIFY_UPDATE_ERR,
1136 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1137 startp, total);
paul718e3742002-12-13 20:15:29 +00001138 return -1;
1139 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001140
1141 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1142 attre->aggregator_as = stream_getl (peer->ibuf);
1143 else
1144 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001145 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001146
1147 /* Set atomic aggregate flag. */
1148 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1149
1150 return 0;
1151}
1152
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001153/* New Aggregator attribute */
1154static int
1155bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1156 struct attr *attr, as_t *as4_aggregator_as,
1157 struct in_addr *as4_aggregator_addr)
1158{
1159 if (length != 8)
1160 {
1161 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1162
1163 bgp_notify_send (peer,
1164 BGP_NOTIFY_UPDATE_ERR,
1165 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1166 return -1;
1167 }
1168 *as4_aggregator_as = stream_getl (peer->ibuf);
1169 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1170
1171 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1172
1173 return 0;
1174}
1175
1176/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1177 */
1178static int
1179bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1180 struct aspath *as4_path, as_t as4_aggregator,
1181 struct in_addr *as4_aggregator_addr)
1182{
1183 int ignore_as4_path = 0;
1184 struct aspath *newpath;
1185 struct attr_extra *attre = attr->extra;
1186
1187 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1188 {
1189 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1190 * if given.
1191 * It is worth a warning though, because the peer really
1192 * should not send them
1193 */
1194 if (BGP_DEBUG(as4, AS4))
1195 {
1196 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1197 zlog_debug ("[AS4] %s %s AS4_PATH",
1198 peer->host, "AS4 capable peer, yet it sent");
1199
1200 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1201 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1202 peer->host, "AS4 capable peer, yet it sent");
1203 }
1204
1205 return 0;
1206 }
1207
1208 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1209 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1210 {
1211 /* Hu? This is not supposed to happen at all!
1212 * got as4_path and no aspath,
1213 * This should already
1214 * have been handled by 'well known attributes missing'
1215 * But... yeah, paranoia
1216 * Take this as a "malformed attribute"
1217 */
1218 zlog (peer->log, LOG_ERR,
1219 "%s BGP not AS4 capable peer sent AS4_PATH but"
1220 " no AS_PATH, cant do anything here", peer->host);
1221 bgp_notify_send (peer,
1222 BGP_NOTIFY_UPDATE_ERR,
1223 BGP_NOTIFY_UPDATE_MAL_ATTR);
1224 return -1;
1225 }
1226
1227 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1228 * because that may override AS4_PATH
1229 */
1230 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1231 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001232 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1233 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001234 assert (attre);
1235
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001236 /* received both.
1237 * if the as_number in aggregator is not AS_TRANS,
1238 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1239 * and the Aggregator shall be taken as
1240 * info on the aggregating node, and the AS_PATH
1241 * shall be taken as the AS_PATH
1242 * otherwise
1243 * the Aggregator shall be ignored and the
1244 * AS4_AGGREGATOR shall be taken as the
1245 * Aggregating node and the AS_PATH is to be
1246 * constructed "as in all other cases"
1247 */
1248 if ( attre->aggregator_as != BGP_AS_TRANS )
1249 {
1250 /* ignore */
1251 if ( BGP_DEBUG(as4, AS4))
1252 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1253 " send AGGREGATOR != AS_TRANS and"
1254 " AS4_AGGREGATOR, so ignore"
1255 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1256 ignore_as4_path = 1;
1257 }
1258 else
1259 {
1260 /* "New_aggregator shall be taken as aggregator" */
1261 attre->aggregator_as = as4_aggregator;
1262 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1263 }
1264 }
1265 else
1266 {
1267 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1268 * That is bogus - but reading the conditions
1269 * we have to handle AS4_AGGREGATOR as if it were
1270 * AGGREGATOR in that case
1271 */
1272 if ( BGP_DEBUG(as4, AS4))
1273 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1274 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1275 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001276 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001277 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1278 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1279 }
1280 }
1281
1282 /* need to reconcile NEW_AS_PATH and AS_PATH */
1283 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1284 {
1285 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1286 aspath_unintern (attr->aspath);
1287 attr->aspath = aspath_intern (newpath);
1288 }
1289 return 0;
1290}
1291
paul718e3742002-12-13 20:15:29 +00001292/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001293static int
paul718e3742002-12-13 20:15:29 +00001294bgp_attr_community (struct peer *peer, bgp_size_t length,
1295 struct attr *attr, u_char flag)
1296{
1297 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001298 {
1299 attr->community = NULL;
1300 return 0;
1301 }
Paul Jakmafc097162010-12-05 17:17:26 +00001302
1303 attr->community =
1304 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1305
1306 /* XXX: fix community_parse to use stream API and remove this */
1307 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001308
Paul Jakmafc097162010-12-05 17:17:26 +00001309 if (!attr->community)
1310 return -1;
1311
paul718e3742002-12-13 20:15:29 +00001312 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1313
1314 return 0;
1315}
1316
1317/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001318static int
paul718e3742002-12-13 20:15:29 +00001319bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienko5de17192011-09-30 15:08:54 +04001320 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001321{
Denis Ovsienko5de17192011-09-30 15:08:54 +04001322 bgp_size_t total;
1323
1324 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1325 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001326 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko5de17192011-09-30 15:08:54 +04001327 {
1328 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1329 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1330 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1331 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1332 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1333 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
1334 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1335 return -1;
1336 }
1337 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001338 if (length != 4)
1339 {
1340 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1341
1342 bgp_notify_send (peer,
1343 BGP_NOTIFY_UPDATE_ERR,
1344 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1345 return -1;
1346 }
1347
Paul Jakmafb982c22007-05-04 20:15:47 +00001348 (bgp_attr_extra_get (attr))->originator_id.s_addr
1349 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001350
1351 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1352
1353 return 0;
1354}
1355
1356/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001357static int
paul718e3742002-12-13 20:15:29 +00001358bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001359 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001360{
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001361 bgp_size_t total;
1362
1363 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1364 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001365 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001366 {
1367 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1368 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1369 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1370 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1371 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1372 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
1373 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1374 return -1;
1375 }
paul718e3742002-12-13 20:15:29 +00001376 /* Check length. */
1377 if (length % 4)
1378 {
1379 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1380
1381 bgp_notify_send (peer,
1382 BGP_NOTIFY_UPDATE_ERR,
1383 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1384 return -1;
1385 }
1386
Paul Jakmafb982c22007-05-04 20:15:47 +00001387 (bgp_attr_extra_get (attr))->cluster
1388 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001389
paul9985f832005-02-09 15:51:56 +00001390 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001391
1392 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1393
1394 return 0;
1395}
1396
1397/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001398int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001399bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1400 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001401{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001402 afi_t afi;
1403 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001404 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001405 size_t start;
paul718e3742002-12-13 20:15:29 +00001406 int ret;
1407 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001408 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001409 bgp_size_t total;
1410
1411 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1412 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001413 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001414 {
1415 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1416 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1417 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1418 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1419 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1420 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
1421 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1422 return -1;
1423 }
paul718e3742002-12-13 20:15:29 +00001424 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001425 s = BGP_INPUT(peer);
1426 start = stream_get_getp(s);
1427
1428 /* safe to read statically sized header? */
1429#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001430#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001431 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001432 {
1433 zlog_info ("%s: %s sent invalid length, %lu",
1434 __func__, peer->host, (unsigned long)length);
1435 return -1;
1436 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001437
paul718e3742002-12-13 20:15:29 +00001438 /* Load AFI, SAFI. */
1439 afi = stream_getw (s);
1440 safi = stream_getc (s);
1441
1442 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001443 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001444
Paul Jakma03292802008-06-07 20:37:10 +00001445 if (LEN_LEFT < attre->mp_nexthop_len)
1446 {
1447 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1448 __func__, peer->host, attre->mp_nexthop_len);
1449 return -1;
1450 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001451
paul718e3742002-12-13 20:15:29 +00001452 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001453 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001454 {
1455 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001456 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001457 /* Probably needed for RFC 2283 */
1458 if (attr->nexthop.s_addr == 0)
1459 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001460 break;
1461 case 12:
1462 {
1463 u_int32_t rd_high;
1464 u_int32_t rd_low;
1465
1466 rd_high = stream_getl (s);
1467 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001468 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001469 }
1470 break;
1471#ifdef HAVE_IPV6
1472 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001473 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001474 break;
1475 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001476 stream_get (&attre->mp_nexthop_global, s, 16);
1477 stream_get (&attre->mp_nexthop_local, s, 16);
1478 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001479 {
1480 char buf1[INET6_ADDRSTRLEN];
1481 char buf2[INET6_ADDRSTRLEN];
1482
1483 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001484 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 +00001485 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001486 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001487 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001488 buf2, INET6_ADDRSTRLEN));
1489
Paul Jakmafb982c22007-05-04 20:15:47 +00001490 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001491 }
1492 break;
1493#endif /* HAVE_IPV6 */
1494 default:
Paul Jakma03292802008-06-07 20:37:10 +00001495 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1496 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001497 return -1;
paul718e3742002-12-13 20:15:29 +00001498 }
1499
Paul Jakma03292802008-06-07 20:37:10 +00001500 if (!LEN_LEFT)
1501 {
1502 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1503 __func__, peer->host);
1504 return -1;
1505 }
paul718e3742002-12-13 20:15:29 +00001506
Paul Jakma6e4ab122007-04-10 19:36:48 +00001507 {
1508 u_char val;
1509 if ((val = stream_getc (s)))
1510 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1511 peer->host, val);
1512 }
1513
1514 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001515 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001516 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001517 {
1518 zlog_info ("%s: (%s) Failed to read NLRI",
1519 __func__, peer->host);
1520 return -1;
1521 }
paul718e3742002-12-13 20:15:29 +00001522
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001523 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001524 {
1525 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001526 if (ret < 0)
1527 {
1528 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1529 __func__, peer->host);
1530 return -1;
1531 }
paul718e3742002-12-13 20:15:29 +00001532 }
1533
1534 mp_update->afi = afi;
1535 mp_update->safi = safi;
1536 mp_update->nlri = stream_pnt (s);
1537 mp_update->length = nlri_len;
1538
paul9985f832005-02-09 15:51:56 +00001539 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001540
1541 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001542#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001543}
1544
1545/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001546int
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001547bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1548 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001549 struct bgp_nlri *mp_withdraw)
1550{
1551 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001552 afi_t afi;
1553 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001554 u_int16_t withdraw_len;
1555 int ret;
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001556 bgp_size_t total;
1557
1558 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1559 /* Flag checks. */
Denis Ovsienko7ebd4702011-10-18 14:20:04 +04001560 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001561 {
1562 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1563 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1564 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1565 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1566 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1567 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
1568 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1569 return -1;
1570 }
paul718e3742002-12-13 20:15:29 +00001571
1572 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001573
1574#define BGP_MP_UNREACH_MIN_SIZE 3
1575 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1576 return -1;
1577
paul718e3742002-12-13 20:15:29 +00001578 afi = stream_getw (s);
1579 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001580
1581 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001582
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001583 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001584 {
1585 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1586 if (ret < 0)
1587 return -1;
1588 }
1589
1590 mp_withdraw->afi = afi;
1591 mp_withdraw->safi = safi;
1592 mp_withdraw->nlri = stream_pnt (s);
1593 mp_withdraw->length = withdraw_len;
1594
paul9985f832005-02-09 15:51:56 +00001595 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001596
1597 return 0;
1598}
1599
1600/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001601static int
paul718e3742002-12-13 20:15:29 +00001602bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1603 struct attr *attr, u_char flag)
1604{
1605 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001606 {
1607 if (attr->extra)
1608 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001609 /* Empty extcomm doesn't seem to be invalid per se */
1610 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001611 }
Paul Jakmafc097162010-12-05 17:17:26 +00001612
1613 (bgp_attr_extra_get (attr))->ecommunity =
1614 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1615 /* XXX: fix ecommunity_parse to use stream API */
1616 stream_forward_getp (peer->ibuf, length);
1617
1618 if (!attr->extra->ecommunity)
1619 return -1;
1620
paul718e3742002-12-13 20:15:29 +00001621 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1622
1623 return 0;
1624}
1625
1626/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001627static int
paul718e3742002-12-13 20:15:29 +00001628bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1629 u_char type, bgp_size_t length, u_char *startp)
1630{
1631 bgp_size_t total;
1632 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001633 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001634
hassof4184462005-02-01 20:13:16 +00001635 if (BGP_DEBUG (normal, NORMAL))
1636 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1637 peer->host, type, length);
1638
paul718e3742002-12-13 20:15:29 +00001639 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001640 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001641 "Unknown attribute type %d length %d is received", type, length);
1642
1643 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001644 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001645
1646 /* Adjest total length to include type and length. */
1647 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1648
1649 /* If any of the mandatory well-known attributes are not recognized,
1650 then the Error Subcode is set to Unrecognized Well-known
1651 Attribute. The Data field contains the unrecognized attribute
1652 (type, length and value). */
1653 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1654 {
1655 /* Adjust startp to do not include flag value. */
1656 bgp_notify_send_with_data (peer,
1657 BGP_NOTIFY_UPDATE_ERR,
1658 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1659 startp, total);
1660 return -1;
1661 }
1662
1663 /* Unrecognized non-transitive optional attributes must be quietly
1664 ignored and not passed along to other BGP peers. */
1665 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1666 return 0;
1667
1668 /* If a path with recognized transitive optional attribute is
1669 accepted and passed along to other BGP peers and the Partial bit
1670 in the Attribute Flags octet is set to 1 by some previous AS, it
1671 is not set back to 0 by the current AS. */
1672 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1673
1674 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001675 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001676 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001677
Paul Jakmafb982c22007-05-04 20:15:47 +00001678 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001679
1680 if (transit->val)
1681 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1682 transit->length + total);
1683 else
1684 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1685
1686 memcpy (transit->val + transit->length, startp, total);
1687 transit->length += total;
1688
1689 return 0;
1690}
1691
1692/* Read attribute of update packet. This function is called from
1693 bgp_update() in bgpd.c. */
1694int
1695bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1696 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1697{
1698 int ret;
1699 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001700 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001701 bgp_size_t length;
1702 u_char *startp, *endp;
1703 u_char *attr_endp;
1704 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001705 /* we need the as4_path only until we have synthesized the as_path with it */
1706 /* same goes for as4_aggregator */
1707 struct aspath *as4_path = NULL;
1708 as_t as4_aggregator = 0;
1709 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001710
1711 /* Initialize bitmap. */
1712 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1713
1714 /* End pointer of BGP attribute. */
1715 endp = BGP_INPUT_PNT (peer) + size;
1716
1717 /* Get attributes to the end of attribute length. */
1718 while (BGP_INPUT_PNT (peer) < endp)
1719 {
1720 /* Check remaining length check.*/
1721 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1722 {
gdtc29fdba2004-12-09 14:46:46 +00001723 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001724 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001725 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001726 peer->host,
1727 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001728
1729 bgp_notify_send (peer,
1730 BGP_NOTIFY_UPDATE_ERR,
1731 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1732 return -1;
1733 }
1734
1735 /* Fetch attribute flag and type. */
1736 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko19e76542011-09-27 15:35:39 +04001737 /* "The lower-order four bits of the Attribute Flags octet are
1738 unused. They MUST be zero when sent and MUST be ignored when
1739 received." */
1740 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001741 type = stream_getc (BGP_INPUT (peer));
1742
Paul Jakma370b64a2007-12-22 16:49:52 +00001743 /* Check whether Extended-Length applies and is in bounds */
1744 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1745 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1746 {
1747 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001748 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001749 peer->host,
1750 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1751
1752 bgp_notify_send (peer,
1753 BGP_NOTIFY_UPDATE_ERR,
1754 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1755 return -1;
1756 }
1757
paul718e3742002-12-13 20:15:29 +00001758 /* Check extended attribue length bit. */
1759 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1760 length = stream_getw (BGP_INPUT (peer));
1761 else
1762 length = stream_getc (BGP_INPUT (peer));
1763
1764 /* If any attribute appears more than once in the UPDATE
1765 message, then the Error Subcode is set to Malformed Attribute
1766 List. */
1767
1768 if (CHECK_BITMAP (seen, type))
1769 {
1770 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001771 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001772 peer->host, type);
1773
1774 bgp_notify_send (peer,
1775 BGP_NOTIFY_UPDATE_ERR,
1776 BGP_NOTIFY_UPDATE_MAL_ATTR);
1777 return -1;
1778 }
1779
1780 /* Set type to bitmap to check duplicate attribute. `type' is
1781 unsigned char so it never overflow bitmap range. */
1782
1783 SET_BITMAP (seen, type);
1784
1785 /* Overflow check. */
1786 attr_endp = BGP_INPUT_PNT (peer) + length;
1787
1788 if (attr_endp > endp)
1789 {
1790 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001791 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
paul718e3742002-12-13 20:15:29 +00001792 bgp_notify_send (peer,
1793 BGP_NOTIFY_UPDATE_ERR,
1794 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1795 return -1;
1796 }
1797
1798 /* OK check attribute and store it's value. */
1799 switch (type)
1800 {
1801 case BGP_ATTR_ORIGIN:
1802 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1803 break;
1804 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001805 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1806 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001807 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001808 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001809 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1810 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001811 break;
paul718e3742002-12-13 20:15:29 +00001812 case BGP_ATTR_NEXT_HOP:
1813 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1814 break;
1815 case BGP_ATTR_MULTI_EXIT_DISC:
1816 ret = bgp_attr_med (peer, length, attr, flag, startp);
1817 break;
1818 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001819 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001820 break;
1821 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienkoca22cc42011-09-20 14:43:50 +04001822 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001823 break;
1824 case BGP_ATTR_AGGREGATOR:
Denis Ovsienko047d6a62011-10-08 13:54:48 +04001825 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001826 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001827 case BGP_ATTR_AS4_AGGREGATOR:
1828 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1829 break;
paul718e3742002-12-13 20:15:29 +00001830 case BGP_ATTR_COMMUNITIES:
1831 ret = bgp_attr_community (peer, length, attr, flag);
1832 break;
1833 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienko5de17192011-09-30 15:08:54 +04001834 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001835 break;
1836 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienkocadc4cf2011-09-30 15:12:17 +04001837 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001838 break;
1839 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001840 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001841 break;
1842 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienkoefb2c332011-10-10 21:08:33 +04001843 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001844 break;
1845 case BGP_ATTR_EXT_COMMUNITIES:
1846 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1847 break;
1848 default:
1849 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1850 break;
1851 }
1852
1853 /* If error occured immediately return to the caller. */
1854 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001855 {
1856 zlog (peer->log, LOG_WARNING,
1857 "%s: Attribute %s, parse error",
1858 peer->host,
1859 LOOKUP (attr_str, type));
1860 bgp_notify_send (peer,
1861 BGP_NOTIFY_UPDATE_ERR,
1862 BGP_NOTIFY_UPDATE_MAL_ATTR);
1863 return ret;
1864 }
paul718e3742002-12-13 20:15:29 +00001865
1866 /* Check the fetched length. */
1867 if (BGP_INPUT_PNT (peer) != attr_endp)
1868 {
1869 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001870 "%s: BGP attribute %s, fetch error",
1871 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001872 bgp_notify_send (peer,
1873 BGP_NOTIFY_UPDATE_ERR,
1874 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1875 return -1;
1876 }
1877 }
1878
1879 /* Check final read pointer is same as end pointer. */
1880 if (BGP_INPUT_PNT (peer) != endp)
1881 {
1882 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001883 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001884 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001885 bgp_notify_send (peer,
1886 BGP_NOTIFY_UPDATE_ERR,
1887 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1888 return -1;
1889 }
1890
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001891 /*
1892 * At this place we can see whether we got AS4_PATH and/or
1893 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1894 * We can not do this before we've read all attributes because
1895 * the as4 handling does not say whether AS4_PATH has to be sent
1896 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1897 * in relationship to AGGREGATOR.
1898 * So, to be defensive, we are not relying on any order and read
1899 * all attributes first, including these 32bit ones, and now,
1900 * afterwards, we look what and if something is to be done for as4.
1901 */
1902 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1903 as4_aggregator, &as4_aggregator_addr))
1904 return -1;
1905
1906 /* At this stage, we have done all fiddling with as4, and the
1907 * resulting info is in attr->aggregator resp. attr->aspath
1908 * so we can chuck as4_aggregator and as4_path alltogether in
1909 * order to save memory
1910 */
1911 if ( as4_path )
1912 {
1913 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1914 as4_path = NULL;
1915 /* The flag that we got this is still there, but that does not
1916 * do any trouble
1917 */
1918 }
1919 /*
1920 * The "rest" of the code does nothing with as4_aggregator.
1921 * there is no memory attached specifically which is not part
1922 * of the attr.
1923 * so ignoring just means do nothing.
1924 */
1925 /*
1926 * Finally do the checks on the aspath we did not do yet
1927 * because we waited for a potentially synthesized aspath.
1928 */
1929 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1930 {
1931 ret = bgp_attr_aspath_check( peer, attr );
1932 if ( ret < 0 )
1933 return ret;
1934 }
1935
paul718e3742002-12-13 20:15:29 +00001936 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001937 if (attr->extra && attr->extra->transit)
1938 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001939
1940 return 0;
1941}
1942
1943/* Well-known attribute check. */
1944int
1945bgp_attr_check (struct peer *peer, struct attr *attr)
1946{
1947 u_char type = 0;
1948
1949 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1950 type = BGP_ATTR_ORIGIN;
1951
1952 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1953 type = BGP_ATTR_AS_PATH;
1954
1955 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1956 type = BGP_ATTR_NEXT_HOP;
1957
1958 if (peer_sort (peer) == BGP_PEER_IBGP
1959 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1960 type = BGP_ATTR_LOCAL_PREF;
1961
1962 if (type)
1963 {
1964 zlog (peer->log, LOG_WARNING,
1965 "%s Missing well-known attribute %d.",
1966 peer->host, type);
1967 bgp_notify_send_with_data (peer,
1968 BGP_NOTIFY_UPDATE_ERR,
1969 BGP_NOTIFY_UPDATE_MISS_ATTR,
1970 &type, 1);
1971 return -1;
1972 }
1973 return 0;
1974}
1975
1976int stream_put_prefix (struct stream *, struct prefix *);
1977
1978/* Make attribute packet. */
1979bgp_size_t
1980bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1981 struct stream *s, struct attr *attr, struct prefix *p,
1982 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001983 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001984{
paulfe69a502005-09-10 16:55:02 +00001985 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001986 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001987 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001988 int send_as4_path = 0;
1989 int send_as4_aggregator = 0;
1990 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001991
1992 if (! bgp)
1993 bgp = bgp_get_default ();
1994
1995 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001996 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001997
1998 /* Origin attribute. */
1999 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2000 stream_putc (s, BGP_ATTR_ORIGIN);
2001 stream_putc (s, 1);
2002 stream_putc (s, attr->origin);
2003
2004 /* AS path attribute. */
2005
2006 /* If remote-peer is EBGP */
2007 if (peer_sort (peer) == BGP_PEER_EBGP
2008 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002009 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002010 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002011 {
2012 aspath = aspath_dup (attr->aspath);
2013
2014 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2015 {
2016 /* Strip the confed info, and then stuff our path CONFED_ID
2017 on the front */
2018 aspath = aspath_delete_confed_seq (aspath);
2019 aspath = aspath_add_seq (aspath, bgp->confed_id);
2020 }
2021 else
2022 {
2023 aspath = aspath_add_seq (aspath, peer->local_as);
2024 if (peer->change_local_as)
2025 aspath = aspath_add_seq (aspath, peer->change_local_as);
2026 }
2027 }
2028 else if (peer_sort (peer) == BGP_PEER_CONFED)
2029 {
2030 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2031 aspath = aspath_dup (attr->aspath);
2032 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2033 }
2034 else
2035 aspath = attr->aspath;
2036
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002037 /* If peer is not AS4 capable, then:
2038 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2039 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2040 * types are in it (i.e. exclude them if they are there)
2041 * AND do this only if there is at least one asnum > 65535 in the path!
2042 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2043 * all ASnums > 65535 to BGP_AS_TRANS
2044 */
paul718e3742002-12-13 20:15:29 +00002045
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002046 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2047 stream_putc (s, BGP_ATTR_AS_PATH);
2048 aspath_sizep = stream_get_endp (s);
2049 stream_putw (s, 0);
2050 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2051
2052 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2053 * in the path
2054 */
2055 if (!use32bit && aspath_has_as4 (aspath))
2056 send_as4_path = 1; /* we'll do this later, at the correct place */
2057
paul718e3742002-12-13 20:15:29 +00002058 /* Nexthop attribute. */
2059 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2060 {
2061 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2062 stream_putc (s, BGP_ATTR_NEXT_HOP);
2063 stream_putc (s, 4);
2064 if (safi == SAFI_MPLS_VPN)
2065 {
2066 if (attr->nexthop.s_addr == 0)
2067 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2068 else
2069 stream_put_ipv4 (s, attr->nexthop.s_addr);
2070 }
2071 else
2072 stream_put_ipv4 (s, attr->nexthop.s_addr);
2073 }
2074
2075 /* MED attribute. */
2076 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2077 {
2078 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2079 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2080 stream_putc (s, 4);
2081 stream_putl (s, attr->med);
2082 }
2083
2084 /* Local preference. */
2085 if (peer_sort (peer) == BGP_PEER_IBGP ||
2086 peer_sort (peer) == BGP_PEER_CONFED)
2087 {
2088 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2089 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2090 stream_putc (s, 4);
2091 stream_putl (s, attr->local_pref);
2092 }
2093
2094 /* Atomic aggregate. */
2095 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2096 {
2097 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2098 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2099 stream_putc (s, 0);
2100 }
2101
2102 /* Aggregator. */
2103 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2104 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002105 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002106
2107 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002108 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2109 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002110
2111 if (use32bit)
2112 {
2113 /* AS4 capable peer */
2114 stream_putc (s, 8);
2115 stream_putl (s, attr->extra->aggregator_as);
2116 }
2117 else
2118 {
2119 /* 2-byte AS peer */
2120 stream_putc (s, 6);
2121
2122 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2123 if ( attr->extra->aggregator_as > 65535 )
2124 {
2125 stream_putw (s, BGP_AS_TRANS);
2126
2127 /* we have to send AS4_AGGREGATOR, too.
2128 * we'll do that later in order to send attributes in ascending
2129 * order.
2130 */
2131 send_as4_aggregator = 1;
2132 }
2133 else
2134 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2135 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002136 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002137 }
2138
2139 /* Community attribute. */
2140 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2141 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2142 {
2143 if (attr->community->size * 4 > 255)
2144 {
2145 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2146 stream_putc (s, BGP_ATTR_COMMUNITIES);
2147 stream_putw (s, attr->community->size * 4);
2148 }
2149 else
2150 {
2151 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2152 stream_putc (s, BGP_ATTR_COMMUNITIES);
2153 stream_putc (s, attr->community->size * 4);
2154 }
2155 stream_put (s, attr->community->val, attr->community->size * 4);
2156 }
2157
2158 /* Route Reflector. */
2159 if (peer_sort (peer) == BGP_PEER_IBGP
2160 && from
2161 && peer_sort (from) == BGP_PEER_IBGP)
2162 {
2163 /* Originator ID. */
2164 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2165 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2166 stream_putc (s, 4);
2167
2168 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002169 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002170 else
2171 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002172
2173 /* Cluster list. */
2174 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2175 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2176
Paul Jakma9eda90c2007-08-30 13:36:17 +00002177 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002178 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002179 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002180 /* If this peer configuration's parent BGP has cluster_id. */
2181 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2182 stream_put_in_addr (s, &bgp->cluster_id);
2183 else
2184 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002185 stream_put (s, attr->extra->cluster->list,
2186 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002187 }
2188 else
2189 {
2190 stream_putc (s, 4);
2191 /* If this peer configuration's parent BGP has cluster_id. */
2192 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2193 stream_put_in_addr (s, &bgp->cluster_id);
2194 else
2195 stream_put_in_addr (s, &bgp->router_id);
2196 }
2197 }
2198
2199#ifdef HAVE_IPV6
2200 /* If p is IPv6 address put it into attribute. */
2201 if (p->family == AF_INET6)
2202 {
2203 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002204 struct attr_extra *attre = attr->extra;
2205
2206 assert (attr->extra);
2207
paul718e3742002-12-13 20:15:29 +00002208 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2209 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002210 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002211 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002212 stream_putw (s, AFI_IP6); /* AFI */
2213 stream_putc (s, safi); /* SAFI */
2214
Paul Jakmafb982c22007-05-04 20:15:47 +00002215 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002216
Paul Jakmafb982c22007-05-04 20:15:47 +00002217 if (attre->mp_nexthop_len == 16)
2218 stream_put (s, &attre->mp_nexthop_global, 16);
2219 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002220 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002221 stream_put (s, &attre->mp_nexthop_global, 16);
2222 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002223 }
2224
2225 /* SNPA */
2226 stream_putc (s, 0);
2227
paul718e3742002-12-13 20:15:29 +00002228 /* Prefix write. */
2229 stream_put_prefix (s, p);
2230
2231 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002232 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002233 }
2234#endif /* HAVE_IPV6 */
2235
2236 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2237 {
2238 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002239
2240 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2241 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002242 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002243 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002244 stream_putw (s, AFI_IP); /* AFI */
2245 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2246
2247 stream_putc (s, 4);
2248 stream_put_ipv4 (s, attr->nexthop.s_addr);
2249
2250 /* SNPA */
2251 stream_putc (s, 0);
2252
paul718e3742002-12-13 20:15:29 +00002253 /* Prefix write. */
2254 stream_put_prefix (s, p);
2255
2256 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002257 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002258 }
2259
2260 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2261 {
2262 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002263
2264 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2265 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002266 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002267 stream_putc (s, 0); /* Length of this attribute. */
2268 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002269 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002270
2271 stream_putc (s, 12);
2272 stream_putl (s, 0);
2273 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002275
2276 /* SNPA */
2277 stream_putc (s, 0);
2278
paul718e3742002-12-13 20:15:29 +00002279 /* Tag, RD, Prefix write. */
2280 stream_putc (s, p->prefixlen + 88);
2281 stream_put (s, tag, 3);
2282 stream_put (s, prd->val, 8);
2283 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2284
2285 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002286 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002287 }
2288
2289 /* Extended Communities attribute. */
2290 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2291 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2292 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002293 struct attr_extra *attre = attr->extra;
2294
2295 assert (attre);
2296
2297 if (peer_sort (peer) == BGP_PEER_IBGP
2298 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002299 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002300 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002301 {
2302 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2303 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002304 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002305 }
2306 else
2307 {
2308 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2309 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002310 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002311 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002312 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002313 }
2314 else
2315 {
paul5228ad22004-06-04 17:58:18 +00002316 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002317 int tbit;
2318 int ecom_tr_size = 0;
2319 int i;
2320
Paul Jakmafb982c22007-05-04 20:15:47 +00002321 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002322 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002323 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002324 tbit = *pnt;
2325
2326 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2327 continue;
2328
2329 ecom_tr_size++;
2330 }
2331
2332 if (ecom_tr_size)
2333 {
2334 if (ecom_tr_size * 8 > 255)
2335 {
2336 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2337 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2338 stream_putw (s, ecom_tr_size * 8);
2339 }
2340 else
2341 {
2342 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2343 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2344 stream_putc (s, ecom_tr_size * 8);
2345 }
2346
Paul Jakmafb982c22007-05-04 20:15:47 +00002347 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002348 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002349 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002350 tbit = *pnt;
2351
2352 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2353 continue;
2354
2355 stream_put (s, pnt, 8);
2356 }
2357 }
paul718e3742002-12-13 20:15:29 +00002358 }
paul718e3742002-12-13 20:15:29 +00002359 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002360
2361 if ( send_as4_path )
2362 {
2363 /* If the peer is NOT As4 capable, AND */
2364 /* there are ASnums > 65535 in path THEN
2365 * give out AS4_PATH */
2366
2367 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2368 * path segments!
2369 * Hm, I wonder... confederation things *should* only be at
2370 * the beginning of an aspath, right? Then we should use
2371 * aspath_delete_confed_seq for this, because it is already
2372 * there! (JK)
2373 * Folks, talk to me: what is reasonable here!?
2374 */
2375 aspath = aspath_delete_confed_seq (aspath);
2376
2377 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2378 stream_putc (s, BGP_ATTR_AS4_PATH);
2379 aspath_sizep = stream_get_endp (s);
2380 stream_putw (s, 0);
2381 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2382 }
2383
2384 if (aspath != attr->aspath)
2385 aspath_free (aspath);
2386
2387 if ( send_as4_aggregator )
2388 {
2389 assert (attr->extra);
2390
2391 /* send AS4_AGGREGATOR, at this place */
2392 /* this section of code moved here in order to ensure the correct
2393 * *ascending* order of attributes
2394 */
2395 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2396 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2397 stream_putc (s, 8);
2398 stream_putl (s, attr->extra->aggregator_as);
2399 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2400 }
Paul Jakma41367172007-08-06 15:24:51 +00002401
paul718e3742002-12-13 20:15:29 +00002402 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002403 if (attr->extra && attr->extra->transit)
2404 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002405
2406 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002407 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002408}
2409
2410bgp_size_t
2411bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2412 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002413 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002414{
2415 unsigned long cp;
2416 unsigned long attrlen_pnt;
2417 bgp_size_t size;
2418
paul9985f832005-02-09 15:51:56 +00002419 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002420
2421 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2422 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2423
paul9985f832005-02-09 15:51:56 +00002424 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002425 stream_putc (s, 0); /* Length of this attribute. */
2426
2427 stream_putw (s, family2afi (p->family));
2428
2429 if (safi == SAFI_MPLS_VPN)
2430 {
2431 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002432 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002433
2434 /* prefix. */
2435 stream_putc (s, p->prefixlen + 88);
2436 stream_put (s, tag, 3);
2437 stream_put (s, prd->val, 8);
2438 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2439 }
2440 else
2441 {
2442 /* SAFI */
2443 stream_putc (s, safi);
2444
2445 /* prefix */
2446 stream_put_prefix (s, p);
2447 }
2448
2449 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002450 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002451 stream_putc_at (s, attrlen_pnt, size);
2452
paul9985f832005-02-09 15:51:56 +00002453 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002454}
2455
2456/* Initialization of attribute. */
2457void
paulfe69a502005-09-10 16:55:02 +00002458bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002459{
paul718e3742002-12-13 20:15:29 +00002460 aspath_init ();
2461 attrhash_init ();
2462 community_init ();
2463 ecommunity_init ();
2464 cluster_init ();
2465 transit_init ();
2466}
2467
Chris Caputo228da422009-07-18 05:44:03 +00002468void
2469bgp_attr_finish (void)
2470{
2471 aspath_finish ();
2472 attrhash_finish ();
2473 community_finish ();
2474 ecommunity_finish ();
2475 cluster_finish ();
2476 transit_finish ();
2477}
2478
paul718e3742002-12-13 20:15:29 +00002479/* Make attribute packet. */
2480void
paula3845922003-10-18 01:30:50 +00002481bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2482 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002483{
2484 unsigned long cp;
2485 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002486 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002487 struct aspath *aspath;
2488
2489 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002490 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002491
2492 /* Place holder of length. */
2493 stream_putw (s, 0);
2494
2495 /* Origin attribute. */
2496 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2497 stream_putc (s, BGP_ATTR_ORIGIN);
2498 stream_putc (s, 1);
2499 stream_putc (s, attr->origin);
2500
2501 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002502
2503 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2504 stream_putc (s, BGP_ATTR_AS_PATH);
2505 aspath_lenp = stream_get_endp (s);
2506 stream_putw (s, 0);
2507
2508 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002509
2510 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002511 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2512 if(prefix != NULL
2513#ifdef HAVE_IPV6
2514 && prefix->family != AF_INET6
2515#endif /* HAVE_IPV6 */
2516 )
2517 {
2518 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2519 stream_putc (s, BGP_ATTR_NEXT_HOP);
2520 stream_putc (s, 4);
2521 stream_put_ipv4 (s, attr->nexthop.s_addr);
2522 }
paul718e3742002-12-13 20:15:29 +00002523
2524 /* MED attribute. */
2525 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2526 {
2527 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2528 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2529 stream_putc (s, 4);
2530 stream_putl (s, attr->med);
2531 }
2532
2533 /* Local preference. */
2534 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2535 {
2536 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2537 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2538 stream_putc (s, 4);
2539 stream_putl (s, attr->local_pref);
2540 }
2541
2542 /* Atomic aggregate. */
2543 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2544 {
2545 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2546 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2547 stream_putc (s, 0);
2548 }
2549
2550 /* Aggregator. */
2551 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2552 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002553 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002554 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2555 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002556 stream_putc (s, 8);
2557 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002558 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002559 }
2560
2561 /* Community attribute. */
2562 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2563 {
2564 if (attr->community->size * 4 > 255)
2565 {
2566 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2567 stream_putc (s, BGP_ATTR_COMMUNITIES);
2568 stream_putw (s, attr->community->size * 4);
2569 }
2570 else
2571 {
2572 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2573 stream_putc (s, BGP_ATTR_COMMUNITIES);
2574 stream_putc (s, attr->community->size * 4);
2575 }
2576 stream_put (s, attr->community->val, attr->community->size * 4);
2577 }
2578
paula3845922003-10-18 01:30:50 +00002579#ifdef HAVE_IPV6
2580 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002581 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2582 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002583 {
2584 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002585 struct attr_extra *attre = attr->extra;
2586
paula3845922003-10-18 01:30:50 +00002587 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2588 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002589 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002590
2591 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002592 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002593 stream_putw(s, AFI_IP6); /* AFI */
2594 stream_putc(s, SAFI_UNICAST); /* SAFI */
2595
2596 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002597 stream_putc(s, attre->mp_nexthop_len);
2598 stream_put(s, &attre->mp_nexthop_global, 16);
2599 if (attre->mp_nexthop_len == 32)
2600 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002601
2602 /* SNPA */
2603 stream_putc(s, 0);
2604
2605 /* Prefix */
2606 stream_put_prefix(s, prefix);
2607
2608 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002609 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002610 }
2611#endif /* HAVE_IPV6 */
2612
paul718e3742002-12-13 20:15:29 +00002613 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002614 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002615 stream_putw_at (s, cp, len);
2616}